Skip to content

Commit 1e97f44

Browse files
authored
CSHARP-4911: Refactor AWS auth library to a separate package (#1421)
1 parent 8447ef1 commit 1e97f44

File tree

166 files changed

+3658
-3111
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

166 files changed

+3658
-3111
lines changed

CSharpDriver.sln

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "FaasTests", "FaasTests", "{
5454
EndProject
5555
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MongoDB.Driver.LambdaTest", "tests\FaasTests\LambdaTests\MongoDB.Driver.LambdaTest\MongoDB.Driver.LambdaTest.csproj", "{33B11279-DA4A-46EA-99BF-9DEDCAC50D95}"
5656
EndProject
57+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MongoDB.Driver.Authentication.AWS", "src\MongoDB.Driver.Authentication.AWS\MongoDB.Driver.Authentication.AWS.csproj", "{16FC2E26-8E6B-4D4A-8330-7639D4039E51}"
58+
EndProject
5759
Global
5860
GlobalSection(SolutionConfigurationPlatforms) = preSolution
5961
Debug|Any CPU = Debug|Any CPU
@@ -112,6 +114,10 @@ Global
112114
{33B11279-DA4A-46EA-99BF-9DEDCAC50D95}.Debug|Any CPU.Build.0 = Debug|Any CPU
113115
{33B11279-DA4A-46EA-99BF-9DEDCAC50D95}.Release|Any CPU.ActiveCfg = Release|Any CPU
114116
{33B11279-DA4A-46EA-99BF-9DEDCAC50D95}.Release|Any CPU.Build.0 = Release|Any CPU
117+
{16FC2E26-8E6B-4D4A-8330-7639D4039E51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
118+
{16FC2E26-8E6B-4D4A-8330-7639D4039E51}.Debug|Any CPU.Build.0 = Debug|Any CPU
119+
{16FC2E26-8E6B-4D4A-8330-7639D4039E51}.Release|Any CPU.ActiveCfg = Release|Any CPU
120+
{16FC2E26-8E6B-4D4A-8330-7639D4039E51}.Release|Any CPU.Build.0 = Release|Any CPU
115121
EndGlobalSection
116122
GlobalSection(SolutionProperties) = preSolution
117123
HideSolutionNode = FALSE
@@ -132,6 +138,7 @@ Global
132138
{CF670F4A-49DD-4030-A4A0-1F4D600EB70A} = {503AB075-7C23-475B-BF7D-E7F751A31536}
133139
{66E1914C-9E10-4B28-915E-AB3773EFDAB2} = {E472BDF5-61F1-461D-872B-9F53BB3ACA80}
134140
{33B11279-DA4A-46EA-99BF-9DEDCAC50D95} = {66E1914C-9E10-4B28-915E-AB3773EFDAB2}
141+
{16FC2E26-8E6B-4D4A-8330-7639D4039E51} = {D2012971-32BB-4C5F-BFC4-30A9994AB152}
135142
EndGlobalSection
136143
GlobalSection(ExtensibilityGlobals) = postSolution
137144
SolutionGuid = {24BEC44B-92B0-43AA-9B15-163459D0C098}

CSharpDriver.sln.DotSettings

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
2+
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=AWS/@EntryIndexedValue">AWS</s:String>
23

34

45
<s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=020B98D17DF67944A12E1EE5B68E5A81/@KeyIndexDefined">True</s:Boolean>

apidocs/api/toc.yml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
items:
2-
- name: MongoDB.Bson
3-
href: MongoDB.Bson/toc.yml
4-
- name: MongoDB.Driver
5-
href: MongoDB.Driver/toc.yml
2+
- href: MongoDB.Bson/toc.yml
3+
- href: MongoDB.Driver/toc.yml
4+
- href: MongoDB.Driver.Authentication.Aws/toc.yml

apidocs/docfx.json

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,38 @@
4545
"memberLayout": "separatePages",
4646
"EnumSortOrder": "declaringOrder",
4747
"allowCompilationErrors": false
48-
}
48+
},
49+
{
50+
"src": [
51+
{
52+
"files": [
53+
"MongoDB.Driver.Authentication.Aws/*.csproj"
54+
],
55+
"exclude": [
56+
"**/bin/**",
57+
"**/obj/**"
58+
],
59+
"src": "../src"
60+
}
61+
],
62+
"dest": "api/MongoDB.Driver.Authentication.Aws",
63+
"includePrivateMembers": false,
64+
"disableGitFeatures": false,
65+
"disableDefaultFilter": false,
66+
"noRestore": false,
67+
"namespaceLayout": "flattened",
68+
"memberLayout": "separatePages",
69+
"EnumSortOrder": "declaringOrder",
70+
"allowCompilationErrors": false
71+
}
4972
],
5073
"build": {
5174
"content": [
5275
{
5376
"files": [
5477
"api/MongoDB.Bson/**.yml",
5578
"api/MongoDB.Driver/**.yml",
79+
"api/MongoDB.Driver.Authentication.Aws/**.yml",
5680
"api/toc.yml",
5781
"api/index.md"
5882
]

evergreen/evergreen.yml

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -939,8 +939,8 @@ functions:
939939
- "mongo-csharp-driver/artifacts/nuget/MongoDB.Bson.${PACKAGE_VERSION}.snupkg"
940940
- "mongo-csharp-driver/artifacts/nuget/MongoDB.Driver.${PACKAGE_VERSION}.nupkg"
941941
- "mongo-csharp-driver/artifacts/nuget/MongoDB.Driver.${PACKAGE_VERSION}.snupkg"
942-
- "mongo-csharp-driver/artifacts/nuget/mongocsharpdriver.${PACKAGE_VERSION}.nupkg"
943-
- "mongo-csharp-driver/artifacts/nuget/mongocsharpdriver.${PACKAGE_VERSION}.snupkg"
942+
- "mongo-csharp-driver/artifacts/nuget/MongoDB.Driver.Authentication.AWS.${PACKAGE_VERSION}.nupkg"
943+
- "mongo-csharp-driver/artifacts/nuget/MongoDB.Driver.Authentication.AWS.${PACKAGE_VERSION}.snupkg"
944944

945945
cleanup:
946946
- command: shell.exec
@@ -1087,6 +1087,20 @@ functions:
10871087
local_file: mongo-csharp-driver/artifacts/nuget/MongoDB.Driver.${PACKAGE_VERSION}.snupkg
10881088
remote_file: ${UPLOAD_BUCKET}/${revision}/MongoDB.Driver.${PACKAGE_VERSION}.snupkg
10891089
bucket: mciuploads
1090+
- command: s3.get
1091+
params:
1092+
aws_key: ${aws_key}
1093+
aws_secret: ${aws_secret}
1094+
local_file: mongo-csharp-driver/artifacts/nuget/MongoDB.Driver.Authentication.AWS.${PACKAGE_VERSION}.nupkg
1095+
remote_file: ${UPLOAD_BUCKET}/${revision}/MongoDB.Driver.Authentication.AWS.${PACKAGE_VERSION}.nupkg
1096+
bucket: mciuploads
1097+
- command: s3.get
1098+
params:
1099+
aws_key: ${aws_key}
1100+
aws_secret: ${aws_secret}
1101+
local_file: mongo-csharp-driver/artifacts/nuget/MongoDB.Driver.Authentication.AWS.${PACKAGE_VERSION}.snupkg
1102+
remote_file: ${UPLOAD_BUCKET}/${revision}/MongoDB.Driver.Authentication.AWS.${PACKAGE_VERSION}.snupkg
1103+
bucket: mciuploads
10901104

10911105
build-apidocs:
10921106
- command: shell.exec

evergreen/push-packages.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ wait_until_package_is_available ()
1919
count=0
2020
echo "Checking package availability: ${package}:${version} at ${packages_search_url}"
2121
while [ -z "$resp" ] && [ $count -le 40 ]; do
22-
resp=$(curl -X GET -s "$packages_search_url?prerelease=true&take=1&q=PackageId:$package" | jq --arg jq_version "$version" '.data[0].versions[] | select(.version==$jq_version) | .version')
22+
resp=$(curl -X GET -s "$packages_search_url?prerelease=true&take=1&q=PackageId:$package" | jq --arg jq_version "$version" '.data[0].versions[]? | select(.version==$jq_version) | .version')
2323
if [ -z "$resp" ]; then
2424
echo "sleeping for 15 seconds..."
2525
sleep 15
@@ -55,7 +55,7 @@ if [ "$PACKAGES_SOURCE" = "https://api.nuget.org/v3/index.json" ] && [[ ! "$PACK
5555
exit 1
5656
fi
5757

58-
PACKAGES=("MongoDB.Bson" "MongoDB.Driver")
58+
PACKAGES=("MongoDB.Bson" "MongoDB.Driver" "MongoDB.Driver.Authentication.AWS")
5959

6060
for package in ${PACKAGES[*]}; do
6161
dotnet nuget verify ./artifacts/nuget/"$package"."$PACKAGE_VERSION".nupkg --certificate-fingerprint "$NUGET_SIGN_CERTIFICATE_FINGERPRINT"

evergreen/run-gssapi-auth-tests.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ else
3737
touch ${PROJECT_DIRECTORY}/evergreen/krb5.conf.empty
3838
export KRB5_CONFIG=${PROJECT_DIRECTORY}/evergreen/krb5.conf.empty
3939

40+
IFS=':' read -ra PARTS <<< "$AUTH_GSSAPI"
41+
USER=$(printf ${PARTS[0]//%/\\x}) # unescape percent-encoded string
42+
PWD=$(printf ${PARTS[1]//%/\\x})
43+
44+
kinit $USER<<<$PWD
45+
4046
for var in TMP TEMP NUGET_PACKAGES NUGET_HTTP_CACHE_PATH APPDATA; do
4147
export $var=/data/tmp;
4248
done
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/* Copyright 2010-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
using MongoDB.Driver.Core.Misc;
17+
18+
namespace MongoDB.Driver.Authentication.AWS
19+
{
20+
internal sealed class AWSCredentials
21+
{
22+
public AWSCredentials(string accessKeyId, string secretAccessKey, string sessionToken)
23+
{
24+
AccessKeyId = Ensure.IsNotNull(accessKeyId, nameof(accessKeyId));
25+
SecretAccessKey = Ensure.IsNotNull(secretAccessKey, nameof(secretAccessKey));
26+
SessionToken = sessionToken; // can be null
27+
}
28+
29+
public string AccessKeyId { get; }
30+
public string SecretAccessKey { get; }
31+
public string SessionToken { get; }
32+
}
33+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/* Copyright 2010-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
using System.Threading;
17+
using System.Threading.Tasks;
18+
using MongoDB.Bson;
19+
using MongoDB.Driver.Authentication.AWS.CredentialsSources;
20+
using MongoDB.Driver.Encryption;
21+
22+
namespace MongoDB.Driver.Authentication.AWS
23+
{
24+
internal sealed class AWSKmsProvider : IKmsProvider
25+
{
26+
public const string ProviderName = "aws";
27+
28+
public static readonly AWSKmsProvider Instance = new AWSKmsProvider();
29+
30+
public async Task<BsonDocument> GetKmsCredentialsAsync(CancellationToken cancellationToken)
31+
{
32+
var credentials = await AWSFallbackCredentialsSource.Instance.GetCredentialsAsync(cancellationToken).ConfigureAwait(false);
33+
34+
return new()
35+
{
36+
{ "accessKeyId", credentials.AccessKeyId },
37+
{ "secretAccessKey", credentials.SecretAccessKey },
38+
{ "sessionToken", credentials.SessionToken, credentials.SessionToken != null }
39+
};
40+
}
41+
}
42+
}
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/* Copyright 2010-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
using System;
17+
using System.Collections.Generic;
18+
using MongoDB.Bson;
19+
using MongoDB.Driver.Authentication.AWS.CredentialsSources;
20+
using MongoDB.Driver.Authentication.AWS.SaslSteps;
21+
using MongoDB.Driver.Core.Connections;
22+
using MongoDB.Driver.Core.Misc;
23+
24+
namespace MongoDB.Driver.Authentication.AWS
25+
{
26+
internal sealed class AWSSaslMechanism : ISaslMechanism
27+
{
28+
public static AWSSaslMechanism Create(SaslContext context)
29+
=> Create(context, RandomByteGenerator.Instance, SystemClock.Instance);
30+
31+
public static AWSSaslMechanism Create(SaslContext context, IRandomByteGenerator randomByteGenerator, IClock clock)
32+
{
33+
Ensure.IsNotNull(context, nameof(context));
34+
Ensure.IsNotNull(randomByteGenerator, nameof(randomByteGenerator));
35+
Ensure.IsNotNull(clock, nameof(clock));
36+
if (context.Mechanism != MechanismName)
37+
{
38+
throw new InvalidOperationException($"Unexpected authentication mechanism: {context.Mechanism}");
39+
}
40+
41+
if (context.Identity.Source != "$external")
42+
{
43+
throw new ArgumentException("MONGODB-AWS authentication may only use the $external source.", nameof(context.Identity.Source));
44+
}
45+
46+
string password = null;
47+
if (context.IdentityEvidence is PasswordEvidence passwordEvidence)
48+
{
49+
password = passwordEvidence.ToInsecureString();
50+
}
51+
52+
var awsCredentials = CreateAwsCredentialsFromMongoCredentials(context.Identity.Username, password, context.MechanismProperties);
53+
IAWSCredentialsSource credentialsSource = awsCredentials != null ? new AWSInstanceCredentialsSource(awsCredentials) : AWSFallbackCredentialsSource.Instance;
54+
55+
return new AWSSaslMechanism(credentialsSource, randomByteGenerator, clock);
56+
}
57+
58+
private static AWSCredentials CreateAwsCredentialsFromMongoCredentials(string username, string password, IEnumerable<KeyValuePair<string, object>> properties)
59+
{
60+
ValidateMechanismProperties(properties);
61+
var sessionToken = ExtractSessionTokenFromMechanismProperties(properties);
62+
63+
if (username == null && password == null && sessionToken == null)
64+
{
65+
return null;
66+
}
67+
if (password != null && username == null)
68+
{
69+
throw new InvalidOperationException("When using MONGODB-AWS authentication if a password is provided via settings then a username must be provided also.");
70+
}
71+
if (username != null && password == null)
72+
{
73+
throw new InvalidOperationException("When using MONGODB-AWS authentication if a username is provided via settings then a password must be provided also.");
74+
}
75+
if (sessionToken != null && (username == null || password == null))
76+
{
77+
throw new InvalidOperationException("When using MONGODB-AWS authentication if a session token is provided via settings then a username and password must be provided also.");
78+
}
79+
80+
return new AWSCredentials(accessKeyId: username, secretAccessKey: password, sessionToken);
81+
}
82+
83+
private static string ExtractSessionTokenFromMechanismProperties(IEnumerable<KeyValuePair<string, object>> properties)
84+
{
85+
if (properties != null)
86+
{
87+
foreach (var pair in properties)
88+
{
89+
if (pair.Key.ToUpperInvariant() == "AWS_SESSION_TOKEN")
90+
{
91+
return (string)pair.Value;
92+
}
93+
}
94+
}
95+
96+
return null;
97+
}
98+
99+
private static void ValidateMechanismProperties(IEnumerable<KeyValuePair<string, object>> properties)
100+
{
101+
if (properties != null)
102+
{
103+
foreach (var pair in properties)
104+
{
105+
if (pair.Key.ToUpperInvariant() != "AWS_SESSION_TOKEN")
106+
{
107+
throw new ArgumentException($"Unknown AWS property '{pair.Key}'.", nameof(properties));
108+
}
109+
}
110+
}
111+
}
112+
113+
public const int ClientNonceLength = 32;
114+
public const string MechanismName = "MONGODB-AWS";
115+
116+
private readonly IClock _clock;
117+
private readonly IAWSCredentialsSource _credentialsSource;
118+
private readonly IRandomByteGenerator _randomByteGenerator;
119+
120+
private AWSSaslMechanism(IAWSCredentialsSource credentialsSource, IRandomByteGenerator randomByteGenerator, IClock clock)
121+
{
122+
_credentialsSource = credentialsSource;
123+
_randomByteGenerator = randomByteGenerator;
124+
_clock = clock;
125+
}
126+
127+
public string DatabaseName => "$external";
128+
129+
public string Name => MechanismName;
130+
131+
public ISaslStep CreateSpeculativeAuthenticationStep() => null;
132+
133+
public BsonDocument CustomizeSaslStartCommand(BsonDocument startCommand) => startCommand;
134+
135+
public ISaslStep Initialize(SaslConversation conversation, ConnectionDescription description)
136+
=> new AWSFirstSaslStep(_credentialsSource, _randomByteGenerator, _clock);
137+
138+
public void OnReAuthenticationRequired()
139+
{
140+
}
141+
142+
public bool TryHandleAuthenticationException(MongoException exception, ISaslStep step, SaslConversation conversation, ConnectionDescription description, out ISaslStep nextStep)
143+
{
144+
_credentialsSource.ResetCache();
145+
nextStep = null;
146+
return false;
147+
}
148+
}
149+
}

0 commit comments

Comments
 (0)