Skip to content

Commit

Permalink
Secure Connection
Browse files Browse the repository at this point in the history
  • Loading branch information
giorgiofran committed Aug 19, 2020
2 parents 72cfdc4 + 20553b1 commit 876a772
Show file tree
Hide file tree
Showing 15 changed files with 288 additions and 52 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@

## Recent change notes

### 0.4.1

* Secure Connection
* The connection string now accepts more than one server.
* Before: only mongodb://www.example.org/test.
* Now it can be: mongodb://www.example.org,www1.example.org,www2.example.org/test
* It is equivalent to: db.pool([mongodb://www.example.org/test, mongodb://www1.example.org/test, mongodb://www2.example.org/test]);
* Added an "uriList" getter in "Db" class.

### 0.4.1-dev.2.2

* Lint clean-up
Expand Down
70 changes: 62 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Server-side driver library for MongoDb implemented in pure Dart.

```dart
Db db = new Db("mongodb://localhost:27017/mongo_dart-blog");
var db = Db("mongodb://localhost:27017/mongo_dart-blog");
await db.open();
```

Expand Down Expand Up @@ -91,13 +91,13 @@ Simple app on base of [JSON ZIPS dataset](https://media.mongodb.org/zips.json)
```dart
import 'package:mongo_dart/mongo_dart.dart';
main() async {
void main() async {
void displayZip(Map zip) {
print(
'state: ${zip["state"]}, city: ${zip["city"]}, zip: ${zip["id"]}, population: ${zip["pop"]}');
}
Db db =
new Db("mongodb://reader:[email protected]:37468/samlple");
var db =
Db("mongodb://reader:[email protected]:37468/samlple");
var zips = db.collection('zip');
await db.open();
print('''
Expand Down Expand Up @@ -145,12 +145,66 @@ main() async {
}
```

### Secure connection

You can connect using a secured tls/ssl connection in one of this two ways:

* setting the secure connection parameter to true in db.open()

```dart
await db.open(secure: true);
```

* adding a query parameter => "tls=true" (or "ssl=true").

```dart
var db = DB('mongodb://www.example.com:27017/test?tls=true&authSource=admin');
or
var db = DB('mongodb://www.example.com:27017/test?ssl=true&authSource=admin');
```

No certificates can be used.

### Atlas (MongoDb cloud service) connection

Atlas requires a tls connection, so now it is possible to connect to this cloud service.
When creating a cluster Atlas shows you three ways of connecting:
Mongo shell, driver and MongoDb Compass Application.
The connection string is in Seedlist Connection Format (starts with mongodb+srv://).
At present this driver does not support this connection string format.
You can do the following:
connect with the mongo shell to the address given by the site, for example:

```bash
mongo "mongodb+srv://cluster0.xtest.mongodb.net/<database name>" --username <your Atlas user>
```

The shell will ask you the password, enter it.

immediately after, the shell will show you the connection string in Standard Connection Format (starting with "mongodb://") in a line starting with "connecting to", for example.

```code
connecting to: mongodb://cluster0-shard-00-00.xtest.mongodb.net:27017,cluster0-shard-00-02.xtest.mongodb.net:27017,cluster0-shard-00-01.xtest.mongodb.net:27017/<database name>?authSource=admin&compressors=disabled&gssapiServiceName=mongodb&replicaSet=atlas-stcn2i-shard-0&ssl=true
```

Copy that string and add your user and password immediately after the "mongodb://" schema in the format "username:password@", for example

```code
mongodb://<your user>:<your password>@cluster0-shard-00-00.xtest.mongodb.net:27017,cluster0-shard-00-02.xtest.mongodb.net:27017,cluster0-shard-00-01.xtest.mongodb.net:27017/<database name>?authSource=admin&compressors=disabled&gssapiServiceName=mongodb&replicaSet=atlas-stcn2i-shard-0&ssl=true
```

Here we are, you can use the latter Connection String in the Db constructor

```dart
var db = Db("mongodb://dbUser:[email protected]:27017,cluster0-shard-00-02.xtest.mongodb.net:27017,cluster0-shard-00-01.xtest.mongodb.net:27017/test-db?authSource=admin&compressors=disabled&gssapiServiceName=mongodb&replicaSet=atlas-stcn2i-shard-0&ssl=true");
```

### See also

- [API Doc](https://pub.dev/documentation/mongo_dart/latest/)
* [API Doc](https://pub.dev/documentation/mongo_dart/latest/)

- [Feature check list](https://github.com/vadimtsushko/mongo_dart/blob/master/doc/feature_checklist.md)
* [Feature check list](https://github.com/vadimtsushko/mongo_dart/blob/master/doc/feature_checklist.md)

- [Recent change notes](https://github.com/vadimtsushko/mongo_dart/blob/master/changelog.md)
* [Recent change notes](https://github.com/vadimtsushko/mongo_dart/blob/master/changelog.md)

- Additional [examples](https://github.com/vadimtsushko/mongo_dart/tree/master/example) and [tests](https://github.com/vadimtsushko/mongo_dart/tree/master/test)
* Additional [examples](https://github.com/vadimtsushko/mongo_dart/tree/master/example) and [tests](https://github.com/vadimtsushko/mongo_dart/tree/master/test)
8 changes: 8 additions & 0 deletions example/example.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ String port = Platform.environment['MONGO_DART_DRIVER_PORT'] ?? '27017';

void main() async {
var db = Db('mongodb://$host:$port/mongo_dart-blog');
// Example url for Atlas connection
/* var db = Db('mongodb://<atlas-user>:<atlas-password>@'
'cluster0-shard-00-02.xtest.mongodb.net:27017,'
'cluster0-shard-00-01.xtest.mongodb.net:27017,'
'cluster0-shard-00-00.xtest.mongodb.net:27017/'
'mongo_dart-blog?authSource=admin&compressors=disabled'
'&gssapiServiceName=mongodb&replicaSet=atlas-stcn2i-shard-0'
'&ssl=true'); */
var authors = <String, Map>{};
var users = <String, Map>{};
await db.open();
Expand Down
2 changes: 1 addition & 1 deletion lib/mongo_dart.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ library mongo_dart;
import 'dart:async';
import 'dart:collection';
import 'dart:convert' show base64, utf8;
import 'dart:io' show File, FileMode, IOSink, Socket;
import 'dart:io' show File, FileMode, IOSink, SecureSocket, Socket;
import 'dart:math';
import 'dart:typed_data';
import 'package:collection/collection.dart';
Expand Down
83 changes: 60 additions & 23 deletions lib/src/database/db.dart
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,12 @@ class WriteConcern {
class _UriParameters {
static const authMechanism = 'authMechanism';
static const authSource = 'authSource';
static const tls = 'tls';
static const ssl = 'ssl';
}

class Db {
final MONGO_DEFAULT_PORT = 27017;
static const mongoDefaultPort = 27017;
final _log = Logger('Db');
final List<String> _uriList = <String>[];

Expand All @@ -143,7 +145,11 @@ class Db {
/// And that code direct to MongoLab server on 37637 port, database *testdb*, username *dart*, password *test*
/// var db = new Db('mongodb://dart:[email protected]:37637/objectory_blog');
Db(String uriString, [this._debugInfo]) {
_uriList.add(uriString);
if (uriString.contains(',')) {
_uriList.addAll(_splitServers(uriString));
} else {
_uriList.add(uriString);
}
}

Db.pool(List<String> uriList, [this._debugInfo]) {
Expand All @@ -156,19 +162,59 @@ class Db {

_Connection get masterConnection => _connectionManager.masterConnection;

ServerConfig _parseUri(String uriString) {
List<String> get uriList => _uriList.toList();

List<String> _splitServers(String uriString) {
String prefix, suffix;
var startServersIndex, endServersIndex;
if (uriString.startsWith('mongodb://')) {
startServersIndex = 10;
} else {
throw MongoDartError('Unexpected scheme in url $uriString. '
'The url is expected to start with "mongodb://"');
}
endServersIndex = uriString.indexOf('/', startServersIndex);
var serversString = uriString.substring(startServersIndex, endServersIndex);
var credentialsIndex = serversString.indexOf('@');
if (credentialsIndex != -1) {
startServersIndex += credentialsIndex + 1;
serversString = uriString.substring(startServersIndex, endServersIndex);
}
prefix = uriString.substring(0, startServersIndex);
suffix = uriString.substring(endServersIndex);
var parts = serversString.split(',');
return [for (var server in parts) '$prefix${server.trim()}$suffix'];
}

ServerConfig _parseUri(String uriString, {bool isSecure}) {
isSecure ??= false;
var uri = Uri.parse(uriString);

if (uri.scheme != 'mongodb') {
throw MongoDartError('Invalid scheme in uri: $uriString ${uri.scheme}');
}

var serverConfig = ServerConfig();
serverConfig.host = uri.host;
serverConfig.port = uri.port;
uri.queryParameters.forEach((String queryParam, String value) {
if (queryParam == _UriParameters.authMechanism) {
selectAuthenticationMechanism(value);
}

if (queryParam == _UriParameters.authSource) {
authSourceDb = Db._authDb(value);
}

if (serverConfig.port == null || serverConfig.port == 0) {
serverConfig.port = MONGO_DEFAULT_PORT;
if ((queryParam == _UriParameters.tls ||
queryParam == _UriParameters.ssl) &&
value == 'true') {
isSecure = true;
}
});

var serverConfig = ServerConfig(
uri.host ?? '127.0.0.1', uri.port ?? mongoDefaultPort, isSecure);

if (serverConfig.port == 0) {
serverConfig.port = mongoDefaultPort;
}

if (uri.userInfo.isNotEmpty) {
Expand All @@ -186,16 +232,6 @@ class Db {
databaseName = uri.path.replaceAll('/', '');
}

uri.queryParameters.forEach((String queryParam, String value) {
if (queryParam == _UriParameters.authMechanism) {
selectAuthenticationMechanism(value);
}

if (queryParam == _UriParameters.authSource) {
authSourceDb = Db._authDb(value);
}
});

return serverConfig;
}

Expand Down Expand Up @@ -255,7 +291,9 @@ class Db {
return section.payload.content;
}

Future open({WriteConcern writeConcern = WriteConcern.ACKNOWLEDGED}) {
Future open(
{WriteConcern writeConcern = WriteConcern.ACKNOWLEDGED,
bool secure = false}) {
return Future.sync(() {
if (state == State.OPENING) {
throw MongoDartError('Attempt to open db in state $state');
Expand All @@ -266,7 +304,7 @@ class Db {
_connectionManager = _ConnectionManager(this);

_uriList.forEach((uri) {
_connectionManager.addConnection(_parseUri(uri));
_connectionManager.addConnection(_parseUri(uri, isSecure: secure));
});

return _connectionManager.open(writeConcern);
Expand Down Expand Up @@ -384,7 +422,7 @@ class Db {
return ListCollectionsCursor(this, filter).stream;
} else {
// Using system collections (pre v3.0 API)
Map selector = <String, dynamic>{};
var selector = <String, dynamic>{};
// If we are limiting the access to a specific collection name
if (filter.containsKey('name')) {
selector['name'] = "${databaseName}.${filter['name']}";
Expand Down Expand Up @@ -599,8 +637,7 @@ class Db {
if (!_masterConnection.serverCapabilities.supportsOpMsg) {
return <String, Object>{};
}
var operation =
ServerStatusOperation(this, options: options);
var operation = ServerStatusOperation(this, options: options);
return operation.execute();
}

Expand Down
4 changes: 3 additions & 1 deletion lib/src/database/info/server_status.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ class ServerStatus {
storageEngineName = serverStatus[keyStorageEngine][keyName];
isPersistent = serverStatus[keyStorageEngine][keyPersistent] ?? true;
if (storageEngineName == keyWiredTiger) {
if (serverStatus[keyWiredTiger][keyLog][keyMaximumLogFileSize] > 0) {
// Atlas service does not return the "wiredTiger" element
if (!serverStatus.containsKey(keyWiredTiger) ||
serverStatus[keyWiredTiger][keyLog][keyMaximumLogFileSize] > 0) {
isJournaled = true;
}
}
Expand Down
5 changes: 2 additions & 3 deletions lib/src/database/operation/create_index_operation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,11 @@ const Set keysToOmit = <String>{
};

class CreateIndexOperation extends CommandOperation {
DbCollection collection;
Object fieldOrSpec;
Map<String, Object> indexes;

CreateIndexOperation(
Db db, this.collection, this.fieldOrSpec, CreateIndexOptions indexOptions)
CreateIndexOperation(Db db, DbCollection collection, this.fieldOrSpec,
CreateIndexOptions indexOptions)
: super(db, indexOptions.options,
collection: collection, aspect: Aspect.writeOperation) {
var indexParameters = parseIndexOptions(fieldOrSpec);
Expand Down
6 changes: 5 additions & 1 deletion lib/src/database/server_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ part of mongo_dart;
class ServerConfig {
String host;
int port;
bool isSecure;
String userName;
String password;
ServerConfig([this.host = '127.0.0.1', this.port = 27017]);
ServerConfig(
[this.host = '127.0.0.1',
this.port = Db.mongoDefaultPort,
this.isSecure = false]);
String get hostUrl => '$host:${port.toString()}';
}
Loading

0 comments on commit 876a772

Please sign in to comment.