Skip to content

Commit

Permalink
auth example
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelmosmann committed Jan 17, 2023
1 parent b16c94d commit 3790180
Show file tree
Hide file tree
Showing 11 changed files with 897 additions and 280 deletions.
226 changes: 226 additions & 0 deletions Howto.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,39 @@ Mongod mongod = new Mongod() {
}
};
...
```

```java
// ...
public class FileStreamProcessor implements StreamProcessor {

private final FileOutputStream outputStream;

public FileStreamProcessor(File file) throws FileNotFoundException {
outputStream = new FileOutputStream(file);
}

@Override
public void process(String block) {
try {
outputStream.write(block.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}

@Override
public void onProcessed() {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}

}
// ...
// <-
```

#### ... to null device
Expand Down Expand Up @@ -300,6 +332,200 @@ try (TransitionWalker.ReachedState<RunningMongodProcess> runningMongoD = transit
}

```

### User/Roles setup

```java

Listener withRunningMongod = EnableAuthentication.of("i-am-admin", "admin-password")
.withEntries(
EnableAuthentication.role("test-db", "test-collection", "can-list-collections")
.withActions("listCollections"),
EnableAuthentication.user("test-db", "read-only", "user-password")
.withRoles("can-list-collections", "read")
).withRunningMongod();

try (TransitionWalker.ReachedState<RunningMongodProcess> running = Mongod.instance()
.withMongodArguments(
Start.to(MongodArguments.class)
.initializedWith(MongodArguments.defaults().withAuth(true)))
.start(Version.Main.PRODUCTION, withRunningMongod)) {

try (MongoClient mongo = new MongoClient(
serverAddress(running.current().getServerAddress()),
MongoCredential.createCredential("i-am-admin", "admin", "admin-password".toCharArray()),
MongoClientOptions.builder().build())) {

MongoDatabase db = mongo.getDatabase("test-db");
MongoCollection<Document> col = db.getCollection("test-collection");
col.insertOne(new Document("testDoc", new Date()));
}

try (MongoClient mongo = new MongoClient(
serverAddress(running.current().getServerAddress()),
MongoCredential.createCredential("read-only", "test-db", "user-password".toCharArray()),
MongoClientOptions.builder().build())) {

MongoDatabase db = mongo.getDatabase("test-db");
MongoCollection<Document> col = db.getCollection("test-collection");
assertThat(col.countDocuments()).isEqualTo(1L);

assertThatThrownBy(() -> col.insertOne(new Document("testDoc", new Date())))
.isInstanceOf(MongoCommandException.class)
.message().contains("not authorized on test-db");
}
}

```

```java
@Value.Immutable
public abstract class EnableAuthentication {
private static Logger LOGGER= LoggerFactory.getLogger(EnableAuthentication.class);

@Value.Parameter
protected abstract String adminUser();
@Value.Parameter
protected abstract String adminPassword();

@Value.Default
protected List<Entry> entries() {
return Collections.emptyList();
}

public interface Entry {

}

@Value.Immutable
public interface Role extends Entry {
@Value.Parameter
String database();
@Value.Parameter
String collection();
@Value.Parameter
String name();
List<String> actions();
}

@Value.Immutable
public interface User extends Entry {
@Value.Parameter
String database();
@Value.Parameter
String username();
@Value.Parameter
String password();
List<String> roles();
}

@Value.Auxiliary
public Listener withRunningMongod() {
StateID<RunningMongodProcess> expectedState = StateID.of(RunningMongodProcess.class);

return Listener.typedBuilder()
.onStateReached(expectedState, running -> {
final ServerAddress address = serverAddress(running);

// Create admin user.
try (final MongoClient clientWithoutCredentials = new MongoClient(address)) {
runCommand(
clientWithoutCredentials.getDatabase("admin"),
commandCreateUser(adminUser(), adminPassword(), Arrays.asList("root"))
);
}

final MongoCredential credentialAdmin =
MongoCredential.createCredential(adminUser(), "admin", adminPassword().toCharArray());

// create roles and users
try (final MongoClient clientAdmin = new MongoClient(address, credentialAdmin, MongoClientOptions.builder().build())) {
entries().forEach(entry -> {
if (entry instanceof Role) {
Role role = (Role) entry;
MongoDatabase db = clientAdmin.getDatabase(role.database());
runCommand(db, commandCreateRole(role.database(), role.collection(), role.name(), role.actions()));
}
if (entry instanceof User) {
User user = (User) entry;
MongoDatabase db = clientAdmin.getDatabase(user.database());
runCommand(db, commandCreateUser(user.username(), user.password(), user.roles()));
}
});
}

})
.onStateTearDown(expectedState, running -> {
final ServerAddress address = serverAddress(running);

final MongoCredential credentialAdmin =
MongoCredential.createCredential(adminUser(), "admin", adminPassword().toCharArray());

try (final MongoClient clientAdmin = new MongoClient(address, credentialAdmin, MongoClientOptions.builder().build())) {
try {
// if success there will be no answer, the connection just closes..
runCommand(
clientAdmin.getDatabase("admin"),
new Document("shutdown", 1)
);
} catch (MongoSocketReadException mx) {
LOGGER.debug("shutdown completed by closing stream");
}
}
})
.build();
}

private static void runCommand(MongoDatabase db, Document document) {
Document result = db.runCommand(document);
boolean success = result.get("ok", Double.class) == 1.0d;
Preconditions.checkArgument(success, "runCommand %s failed: %s", document, result);
}

private static Document commandCreateRole(
String database,
String collection,
String roleName,
List<String> actions
) {
return new Document("createRole", roleName)
.append("privileges", Collections.singletonList(
new Document("resource",
new Document("db", database)
.append("collection", collection))
.append("actions", actions)
)
).append("roles", Collections.emptyList());
}

static Document commandCreateUser(
final String username,
final String password,
final List<String> roles
) {
return new Document("createUser", username)
.append("pwd", password)
.append("roles", roles);
}

private static ServerAddress serverAddress(RunningMongodProcess running) {
de.flapdoodle.embed.mongo.commands.ServerAddress serverAddress = running.getServerAddress();
return new ServerAddress(serverAddress.getHost(), serverAddress.getPort());
}

public static ImmutableRole role(String database, String collection, String name) {
return ImmutableRole.of(database, collection, name);
}

public static ImmutableUser user(String database, String username, String password) {
return ImmutableUser.of(database, username, password);
}

public static ImmutableEnableAuthentication of(String adminUser, String adminPassword) {
return ImmutableEnableAuthentication.of(adminUser,adminPassword);
}
}
```

----

Expand Down
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.24.1</version>
<version>3.24.2</version>
<scope>test</scope>
</dependency>
<dependency>
Expand Down Expand Up @@ -489,7 +489,7 @@
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.process</artifactId>
<version>4.3.5</version>
<version>4.4.2</version>
</dependency>
<dependency>
<groupId>de.flapdoodle.embed</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,14 @@ private static List<String> getCommandLine(
config.params().forEach((key, val) -> builder.add("--setParameter", format("%s=%s", key, val)));
config.args().forEach(builder::add);

if (config.auth()) {
LOGGER.info(
"\n---------------------------------------\n"
+ "hint: auth==true starts mongod with authorization enabled, which, if started from scratch must fail, as a "
+ "connect is only possible for known user.\n"
+ "---------------------------------------\n");
}

builder.add(config.auth() ? "--auth" : "--noauth");

builder.addIf(!version.enabled(Feature.DISABLE_USE_PREALLOC) && config.useNoPrealloc(), "--noprealloc");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,10 @@ public Transitions transitions(de.flapdoodle.embed.process.distribution.Version
}

@Value.Auxiliary
public TransitionWalker.ReachedState<RunningMongodProcess> start(Version version) {
public TransitionWalker.ReachedState<RunningMongodProcess> start(Version version, Listener... listener) {
return transitions(version)
.walker()
.initState(StateID.of(RunningMongodProcess.class));
.initState(StateID.of(RunningMongodProcess.class), listener);
}

public static ImmutableMongod instance() {
Expand Down
Loading

0 comments on commit 3790180

Please sign in to comment.