MongoDB Program New Database Authentication Fails - mongodb

I have a remote tenant database application using MongoDB with authentication enabled. During run-time, I have to programmatically create a new tenant database, create a new tenant database user, create a new collection, and write to the new database with user metadata. My problem is that I am not setting up the tenant user authorization correctly. I am able to create the new tenant database and a database user with role credentials "readWrite". I also can correctly write the document to the "users" collection. If I use my admin credentials, I can access the Tenant database and examine the users document with no issue. However, if I try to later access the database with the newly created database user credentials I get an incorrect user credentials exception. Below is my code that creates the new tenant database,
MongoCredential adminCredentials = MongoCredential
.createCredential(adminuid, admindb, adminpw.toCharArray());
ServerAddress adminSA = new ServerAddress(mongoConnectionUri, mongoPort);
// Create the Mongo Password Vault Client & Document Template
MongoClient adminclient = new MongoClient(adminSA, Arrays.asList(adminCredtials)):
MongoClient adminclient MongoClient(adminSA,Arrays.asList(adminCredentials));
DB tenant = adminclient.getDB(tenantdb);
// Create pwvdb user
DBObject pwvdbrole = new BasicDBObject();
pwvdbrole.put("role", pwvrole);
pwvdbrole.put("db", pwvdb);
ArrayList<DBObject> pwvdbroles = new ArrayList<DBObject>();
pwvdbroles.add(pwvdbrole);
DBObject pwvaultcmd = new BasicDBObject();
pwvaultcmd.put("createUser", pwvuid);
pwvaultcmd.put("pwd", pwvpw);
pwvaultcmd.put("roles", pwvdbroles);
CommandResult result = tenant.command(pwvaultcmd);
if (result.ok()) {
System.out.println("Tenant Credentials: OK");
} else {
System.out.println("Tenant Credentials Error: " +
result.getErrorMessage());
}
// Create users Collection
DBCollection tenantCollection =
tenant.getCollection(tenantcollection);
// Create user default credentials & update user collection
BasicDBObject userdocument = new BasicDBObject();
userdocument.put("firstname", userfirstname);
userdocument.put("lastname", userlastname);
userdocument.put("email", useremail);
userdocument.put("username", username);
userdocument.put("password", pwencoder.encode(userpassword));
userdocument.put("role", Integer.parseInt(userrole));
// Create admin web portal users uid/pw
tenantCollection.insert(userdocument);
pwvclient.close();
Because the client is remote, I use my admin userid, pw, and db for the credentials. However, the MongoDB tenant client is setup using the new tenant database name. This is probably where I am going wrong but I don't know how to remotely access the database with a user I have not created yet. These databases are created at run time and I do not know the name of the tenant user when the application starts.

there are two different places for user permissions to be created, which can be confusing. Both can be done dynamically in your code.
User roles in tenant DB
The easiest option is for you to create the user you want in the tenant DB. You should use the runCommand call with the document structure for the createUser command documented here. You would create this user in the tenant DB. The role should be readWrite or any others documented.
Then later you would authenticate for the user and password for that same DB.
You can also centralize all of your user management in the Admin DB with each createUser call enumerating the roles for each DB/role pair you want. Let me know if you need that explanation. It works basically the same way to create users there and authenticate against that DB also. Then you switch to the DB you want to access on the same MongoClient.
I could not post 2 other helpful links because of strange limitation on posting more than 2 links if I am not an active enough poster (10 reputation).

Here is what I did to get it to work. The two key things I want to point out is the adminops and testops MongoDB templates. Notice that in adminops I used my MongoDB admin credentials but pointed to the testdb. In testops I used my new testdb credentials and point to testdb as well. My error was with adminops. I used the admindb which was incorrect. Also getting the roleobj and cmd was a little tricky but I eventially figured it out.
package com.belcan;
import java.util.ArrayList;
import java.util.Arrays;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
import com.mongodb.BasicDBObject;
import com.mongodb.CommandResult;
import com.mongodb.DBObject;
import com.mongodb.MongoClient;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
#SpringBootApplication(exclude = {MongoAutoConfiguration.class, MongoDataAutoConfiguration.class})
public class PreConfigTestApplication implements CommandLineRunner {
public static void main(String[] args) {
// Fire off Spring Boot & Embedded Linux
SpringApplication.run(PreConfigTestApplication.class, args);
}
#Override
public void run(String...args) throws Exception {
String testdb = "testdb";
String testuid = "skm";
String testpw = "password";
// Set up credentials
MongoCredential admincredentials = MongoCredential
.createCredential(adminuid, admindb, adminpw.toCharArray());
ServerAddress adminsa = new ServerAddress(mongoConnectionUri, mongoPort);
// Create the Mongo Client & Document Template
MongoClient adminclient = new MongoClient(adminsa,Arrays.asList(admincredentials));
MongoOperations adminops = new MongoTemplate(adminclient, testdb);
// First create new user
DBObject roleobj = new BasicDBObject();
roleobj.put("role", "readWrite");
roleobj.put("db", "testdb");
ArrayList<DBObject> array = new ArrayList<DBObject>();
array.add(roleobj);
DBObject cmd = new BasicDBObject();
cmd.put("createUser", testuid);
cmd.put("pwd", testpw);
cmd.put("roles", array);
// Create new User
CommandResult result = (CommandResult) adminops.executeCommand(cmd);
// check to see if command is ok
if (result.ok()) {
System.out.println("createUser Command: OK");
} else {
System.out.println("createUser Error:" + result.getErrorMessage());
}
// switch to testdb
MongoOperations testops = new MongoTemplate(adminclient, testdb);
// Create the user object
User user = new User();
user.setFirstname("mickey");
user.setLastname("mouse");
user.setEmail("mmouse#gmail.com");
user.setUsername("mmouse");
user.setPassword("mmouse1");
user.setRole("USER");
user.setStatus("ACTIVE");
// Now save it
testops.save(user, "users");
// Close Database Connection
adminclient.close();
//
// Now see if we can open the file with the new uid/pw
//
// Set up credentials
MongoCredential testcredentials = MongoCredential
.createCredential(testuid, testdb, testpw.toCharArray());
ServerAddress testsa = new ServerAddress(mongoConnectionUri, mongoPort);
// Create the Mongo Client & Document Template
MongoClient testclient = new MongoClient(testsa,Arrays.asList(testcredentials));
MongoOperations myops = new MongoTemplate(testclient, testdb);
User myuser = new User();
myuser.setFirstname("Daffy");
myuser.setLastname("Duck");
myuser.setEmail("dduck#gmail.com");
myuser.setUsername("dduck");
myuser.setPassword("dduck1");
myuser.setRole("USER");
myuser.setStatus("ACTIVE");
// Now save it
myops.save(myuser,"users");
// Lets print it out
System.out.println("Print Results");
ArrayList<User> userout = (ArrayList<User>) myops.findAll(User.class, "users");
for (int i = 0; i < userout.size(); i++) {
System.out.println(userout.get(i));
}
System.out.println("\n\nAll Done....");
// Close the database
testclient.close();
}
// MongoDB Connection URI
#Value("${spring.data.mongodb.uri}")
private String mongoConnectionUri;
// MongoDB Connection Port
#Value("${spring.data.mongodb.port}")
private int mongoPort;
// MongoDB userid
#Value("${mongo.server.admin.db}")
private String admindb;
// MongoDB admin password
#Value("${mongo.server.admin.pw}")
private String adminpw;
// MongoDB admin userid
#Value("${mongo.server.admin.uid}")
private String adminuid;
}

Related

Adding new roles JHipster and MongoDb

I'm creating application using JHipster and MongoDb and I'm trying to add new roles.
I added new constants to security/AuthoritiesConstants but in my collection jhi_authorities I'm not seeing changes.
Is anybody knows how to add my new role to this collection?
You must also add your new authorities to MongoDb, see InitialSetupMigration.java, either add them here or create a new migration.
See doc
Create new #ChangeLg and write method with #ChangeSet
Like this example
#ChangeLog(order = "002")
public class AddOthersAuthorities {
#ChangeSet(order = "01", author = "initiator", id = "03-addOthersAuthorities")
public void addAuthorities(DB db) {
DBCollection authorityCollection = db.getCollection("jhi_authority");
// Role for super administration
authorityCollection.insert(
BasicDBObjectBuilder.start()
.add("_id", "ROLE_SUPER_ADMIN")
.get());
// Role for company administration
authorityCollection.insert(
BasicDBObjectBuilder.start()
.add("_id", "ROLE_COMPANY_ADMIN")
.get());
// Role for branch administration
authorityCollection.insert(
BasicDBObjectBuilder.start()
.add("_id", "ROLE_BRANCH_ADMIN")
.get());
// Role for employee
authorityCollection.insert(
BasicDBObjectBuilder.start()
.add("_id", "ROLE_EMPLOYEE")
.get());
// Role for registred customer
authorityCollection.insert(
BasicDBObjectBuilder.start()
.add("_id", "ROLE_CUSTOMER")
.get());
// Role for non registred customer
authorityCollection.insert(
BasicDBObjectBuilder.start()
.add("_id", "ROLE_GUEST")
.get());
}
}

How to generate password policy based password in OIM 11gr2ps2

I am creating a event handler to modify user password using OIM UserManager API. But now I need to consider password policy and then generate new password that is compatible with the password policy defined in OIM.
Can you please point to some APIs and Methods which can help here?
import oracle.idm.common.ipf.api.password.RandomPasswordGenerator;
import oracle.idm.common.ipf.api.password.RandomPasswordGeneratorImpl;
The classes above actually gives handle on the randomly generated password that I was looking for. The code below shows the implementation for the same.
PasswordPolicyInfo passwordPolicyInfo = ((PasswordMgmtService)Platform.getService(PasswordMgmtService.class)).getApplicablePasswordPolicy(entityId, Boolean.valueOf(false));
RandomPasswordGenerator randomPasswordGenerator = new RandomPasswordGeneratorImpl();
OimPasswordPolicy policy = new OimPasswordPolicy(Utils.getIpfPasswordPolicyInfoVO(passwordPolicyInfo));
policy.setId(passwordPolicyInfo.getId());
policy.setName(passwordPolicyInfo.getName());
char[] generatedPassword = randomPasswordGenerator.generatePassword(policy, null);
Alternatively by using below OIM API's,you can generate password and also validate it against any policy in OIM:
import oracle.iam.passwordmgmt.api.PasswordMgmtService;
import oracle.iam.passwordmgmt.domain.generator.RandomPasswordGeneratorImpl;
Here is the snippet:
RandomPasswordGeneratorImpl randomPasswordGenerator = new RandomPasswordGeneratorImpl();
UserRepository userRepository = new DBUserRepository();
UserInfo usrInfo = userRepository.getUserAndManagerInfo(usrLogin);
String generatedPassword = new String(randomPasswordGenerator.generatePassword(Utils.getUser(usrInfo)));
PasswordMgmtService passMgmt = Platform.getService(PasswordMgmtService.class);
ValidationResult result = passMgmt.validatePasswordAgainstPolicy(generatedPassword.toCharArray(), Utils.getUser(usrInfo), Locale.getDefault());
You can use PasswordMgmtService api provided by OIM.
You can use below method in you password generation logic in your event handler code.
PasswordPolicyDescription getApplicablePasswordPolicyDescription(java.lang.String userID)
In the PasswordPolicyDescription object you have all properties which were configured while creating Password Policy.

How can I authenticate any database with given username and password in Mongo Java Driver 2.13.0?

Previously I could use db.authenticate(String username, char[] password) method. With 2.13.0, how can I achieve this?
There is no replacement for db.authenticate(). The driver will use the credentials provided and make sure the connections are authenticated as they are created.
Based on this mongodb-user discussion the Java Driver team is open to discussions on what the real need for the db.authenticate(...) method.
Use
import com.mongodb.MongoCredential;
MongoCredential mongoCred =
MongoCredential.createMongoCRCredential(String username, String
dbName, char[] password);
and create mongoclient using mongocredentials
com.mongodb.MongoClient.MongoClient(List seeds, List
credentialsList, MongoClientOptions options)
We can have user-password based authentication for databases, in that case we need to provide authorization credentials like below for new version.
MongoCredential journaldevAuth = MongoCredential.createPlainCredential("pankaj", "journaldev", "pankaj123".toCharArray());
MongoCredential testAuth = MongoCredential.createPlainCredential("pankaj", "test", "pankaj123".toCharArray());
List<MongoCredential> auths = new ArrayList<MongoCredential>();
auths.add(journaldevAuth);
auths.add(testAuth);
ServerAddress serverAddress = new ServerAddress("localhost", 27017);
MongoClient mongo = new MongoClient(serverAddress, auths);
If you are using older versions, you need to provide authentication details after getting the DB object like below
MongoClient mongo = new MongoClient("localhost", 27017);
DB db = mongo.getDB("journaldev");
boolean auth = db.authenticate("pankaj", "pankaj123".toCharArray());

How to correctly authorize into Mongo server using Scala?

I have added authorization to my Mongo database and now I can't perform any queries whats so ever.
Every time I try I get:
reactivemongo.core.commands.DefaultCommandError: BSONCommandError['command failed because the 'ok' field is missing or equals 0'] with original doc {
ok: BSONDouble(0.0),
errmsg: BSONString(unauthorized)
}
And my Authorization bit seams to be alright but it is just not doing the job:
private val driver = new MongoDriver(actorSystem)
private val dbName = "myDatabase"
private val userName = "root"
private val password = "pass"
private val credentials = Seq(Authenticate(dbName, userName, password))
private val connection = driver.connection(List("111.111.111.11"), credentials)
//connection.authenticate(dbName, userName, password)
private val db = connection(dbName)
The user credentials were created
Any ideas on what is wrong here?
Apparently unauthorized means not that I has not logged in it means that the user does not have sufficient permissions or Roles as they are grouped in Mongo.
Some tutorials about adding authorization have skipped that part er go I get to relearn the lesson of reading an official documentation of any resource again...
http://docs.mongodb.org/manual/reference/method/db.addUser/

ServiceStack: How to deal with user registration

I'm trying to understand how to create a SignIn/SignUp service with ServiceStack and my database of choice is MongoDB:
public class AppHost : AppHostBase
{
public AppHost() : base("My Web Services", typeof(WelcomeService).Assembly) {}
public override void Configure(Container container)
{
Plugins.Add(new AuthFeature(() => new AuthUserSession(), new IAuthProvider[] {
new BasicAuthProvider()
}));
Plugins.Add(new RegistrationFeature());
var connectionString = ConfigurationManager.ConnectionStrings["mongodb"].ConnectionString;
var mongoClient = new MongoClient(connectionString);
var server = mongoClient.GetServer();
var db = server.GetDatabase("auth");
container.Register<ICacheClient>(new MemoryCacheClient());
container.Register<IUserAuthRepository>(new MongoDBAuthRepository(db, true));
}
The code above works correctly... it connects to the MongoDB server and creates the user table in the auth database. So far so good... What I'm trying to understand is how the built-in registration service works. If you look at my code, I enabled the RegistrationFeature but when I try to invoke it with http://localhost/register I always get a NotImplementedException. Does this mean I have to implement it from scratch? Is there any additional package to install? How do I actually invoke the default registration feature?