From 9b50ff9275bac8420239234a2f00d980a750dc32 Mon Sep 17 00:00:00 2001 From: hiranya911 Date: Sun, 20 Jan 2019 23:15:09 -0800 Subject: [PATCH 01/13] Adding Stylecop based linting --- FirebaseAdmin/FirebaseAdmin/AppOptions.cs | 24 ++-- .../FirebaseAdmin/Auth/FirebaseAuth.cs | 80 ++++++------ .../FirebaseAdmin/Auth/FirebaseToken.cs | 24 ++-- .../Auth/FirebaseTokenFactory.cs | 80 +++++++----- .../Auth/FirebaseTokenVerifier.cs | 21 +++- .../FirebaseAdmin/Auth/HttpPublicKeySource.cs | 6 +- FirebaseAdmin/FirebaseAdmin/Auth/IAMSigner.cs | 15 ++- FirebaseAdmin/FirebaseAdmin/Auth/ISigner.cs | 2 +- FirebaseAdmin/FirebaseAdmin/Auth/JwtUtils.cs | 10 +- FirebaseAdmin/FirebaseAdmin/Auth/PublicKey.cs | 12 +- .../Auth/ServiceAccountSigner.cs | 4 +- FirebaseAdmin/FirebaseAdmin/Extensions.cs | 7 +- .../FirebaseAdmin/FirebaseAdmin.csproj | 2 + FirebaseAdmin/FirebaseAdmin/FirebaseApp.cs | 116 +++++++++--------- .../FirebaseAdmin/FirebaseException.cs | 10 +- stylecop.ruleset | 30 +++++ 16 files changed, 254 insertions(+), 189 deletions(-) create mode 100644 stylecop.ruleset diff --git a/FirebaseAdmin/FirebaseAdmin/AppOptions.cs b/FirebaseAdmin/FirebaseAdmin/AppOptions.cs index e5ff1fbc..e7a31aaa 100644 --- a/FirebaseAdmin/FirebaseAdmin/AppOptions.cs +++ b/FirebaseAdmin/FirebaseAdmin/AppOptions.cs @@ -25,6 +25,18 @@ namespace FirebaseAdmin /// public sealed class AppOptions { + /// + /// Initializes a new instance of the class. + /// + public AppOptions() {} + + internal AppOptions(AppOptions options) + { + Credential = options.Credential; + ProjectId = options.ProjectId; + ServiceAccountId = options.ServiceAccountId; + } + /// /// used to authorize an app. All service calls made by /// the app will be authorized using this. @@ -44,17 +56,5 @@ public sealed class AppOptions /// JSON. /// public string ServiceAccountId { get; set; } - - /// - /// Creates a new instance. - /// - public AppOptions() {} - - internal AppOptions(AppOptions options) - { - Credential = options.Credential; - ProjectId = options.ProjectId; - ServiceAccountId = options.ServiceAccountId; - } } } diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs index 46426122..756fa246 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs @@ -26,20 +26,56 @@ namespace FirebaseAdmin.Auth public sealed class FirebaseAuth: IFirebaseService { private readonly FirebaseApp _app; - private bool _deleted; private readonly Lazy _tokenFactory; private readonly Lazy _idTokenVerifier; - private readonly Object _lock = new Object(); + private readonly object _lock = new object(); + private bool _deleted; private FirebaseAuth(FirebaseApp app) { _app = app; - _tokenFactory = new Lazy(() => + _tokenFactory = new Lazy(() => FirebaseTokenFactory.Create(_app), true); - _idTokenVerifier = new Lazy(() => + _idTokenVerifier = new Lazy(() => FirebaseTokenVerifier.CreateIDTokenVerifier(_app), true); } + /// + /// The auth instance associated with the default Firebase app. This property is + /// null if the default app doesn't yet exist. + /// + public static FirebaseAuth DefaultInstance + { + get + { + var app = FirebaseApp.DefaultInstance; + if (app == null) + { + return null; + } + return GetAuth(app); + } + } + + /// + /// Returns the auth instance for the specified app. + /// + /// The instance associated with the specified + /// app. + /// If the app argument is null. + /// An app instance. + public static FirebaseAuth GetAuth(FirebaseApp app) + { + if (app == null) + { + throw new ArgumentNullException("App argument must not be null."); + } + return app.GetOrInit(typeof(FirebaseAuth).Name, () => + { + return new FirebaseAuth(app); + }); + } + /// /// Creates a Firebase custom token for the given user ID. This token can then be sent /// back to a client application to be used with the @@ -247,41 +283,5 @@ void IFirebaseService.Delete() } } } - - /// - /// The auth instance associated with the default Firebase app. This property is - /// null if the default app doesn't yet exist. - /// - public static FirebaseAuth DefaultInstance - { - get - { - var app = FirebaseApp.DefaultInstance; - if (app == null) - { - return null; - } - return GetAuth(app); - } - } - - /// - /// Returns the auth instance for the specified app. - /// - /// The instance associated with the specified - /// app. - /// If the app argument is null. - /// An app instance. - public static FirebaseAuth GetAuth(FirebaseApp app) - { - if (app == null) - { - throw new ArgumentNullException("App argument must not be null."); - } - return app.GetOrInit(typeof(FirebaseAuth).Name, () => - { - return new FirebaseAuth(app); - }); - } } } diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseToken.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseToken.cs index e9c0c7e3..2e8487b6 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseToken.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseToken.cs @@ -23,6 +23,17 @@ namespace FirebaseAdmin.Auth /// public sealed class FirebaseToken { + internal FirebaseToken(FirebaseTokenArgs args) + { + Issuer = args.Issuer; + Subject = args.Subject; + Audience = args.Audience; + ExpirationTimeSeconds = args.ExpirationTimeSeconds; + IssuedAtTimeSeconds = args.IssuedAtTimeSeconds; + Uid = args.Subject; + Claims = args.Claims; + } + /// /// The issuer claim that identifies the principal that issued the JWT. /// @@ -48,7 +59,7 @@ public sealed class FirebaseToken /// The issued at claim that identifies the time (in seconds) at which the JWT was issued. /// public long IssuedAtTimeSeconds { get; private set; } - + /// /// User ID of the user to which this ID token belongs. This is same as Subject. /// @@ -59,17 +70,6 @@ public sealed class FirebaseToken /// access custom claims of the token. /// public IReadOnlyDictionary Claims { get; private set; } - - internal FirebaseToken(FirebaseTokenArgs args) - { - Issuer = args.Issuer; - Subject = args.Subject; - Audience = args.Audience; - ExpirationTimeSeconds = args.ExpirationTimeSeconds; - IssuedAtTimeSeconds = args.IssuedAtTimeSeconds; - Uid = args.Subject; - Claims = args.Claims; - } } internal sealed class FirebaseTokenArgs diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenFactory.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenFactory.cs index 79e3b4ab..f6f6b6ac 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenFactory.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenFactory.cs @@ -17,7 +17,7 @@ using System.Collections.Immutable; using System.Text; using System.Threading; -using System.Threading.Tasks; +using System.Threading.Tasks; using System.Runtime.CompilerServices; using Google.Apis.Auth; using Google.Apis.Http; @@ -39,14 +39,28 @@ internal class FirebaseTokenFactory: IDisposable { public const string FirebaseAudience = "https://identitytoolkit.googleapis.com/" + "google.identity.identitytoolkit.v1.IdentityToolkit"; - + public const int TokenDurationSeconds = 3600; public static readonly DateTime UnixEpoch = new DateTime( 1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + public static readonly ImmutableList ReservedClaims = ImmutableList.Create( - "acr", "amr", "at_hash", "aud", "auth_time", "azp", "cnf", "c_hash", - "exp", "firebase", "iat", "iss", "jti", "nbf", "nonce", "sub" - ); + "acr", + "amr", + "at_hash", + "aud", + "auth_time", + "azp", + "cnf", + "c_hash", + "exp", + "firebase", + "iat", + "iss", + "jti", + "nbf", + "nonce", + "sub"); private readonly ISigner _signer; private readonly IClock _clock; @@ -57,6 +71,31 @@ public FirebaseTokenFactory(ISigner signer, IClock clock) _clock = clock.ThrowIfNull(nameof(clock)); } + public static FirebaseTokenFactory Create(FirebaseApp app) + { + ISigner signer = null; + var serviceAccount = app.Options.Credential.ToServiceAccountCredential(); + if (serviceAccount != null) + { + // If the app was initialized with a service account, use it to sign + // tokens locally. + signer = new ServiceAccountSigner(serviceAccount); + } + else if (string.IsNullOrEmpty(app.Options.ServiceAccountId)) + { + // If no service account ID is specified, attempt to discover one and invoke the + // IAM service with it. + signer = new IAMSigner(new HttpClientFactory(), app.Options.Credential); + } + else + { + // If a service account ID is specified, invoke the IAM service with it. + signer = new FixedAccountIAMSigner( + new HttpClientFactory(), app.Options.Credential, app.Options.ServiceAccountId); + } + return new FirebaseTokenFactory(signer, SystemClock.Default); + } + public async Task CreateCustomTokenAsync( string uid, IDictionary developerClaims = null, @@ -85,9 +124,9 @@ public async Task CreateCustomTokenAsync( var header = new JsonWebSignature.Header() { Algorithm = "RS256", - Type = "JWT" + Type = "JWT", }; - + var issued = (int)(_clock.UtcNow - UnixEpoch).TotalSeconds; var keyId = await _signer.GetKeyIdAsync(cancellationToken).ConfigureAwait(false); var payload = new CustomTokenPayload() @@ -97,7 +136,7 @@ public async Task CreateCustomTokenAsync( Subject = keyId, Audience = FirebaseAudience, IssuedAtTimeSeconds = issued, - ExpirationTimeSeconds = issued + TokenDurationSeconds, + ExpirationTimeSeconds = issued + TokenDurationSeconds, }; if (developerClaims != null && developerClaims.Count > 0) { @@ -111,31 +150,6 @@ public void Dispose() { _signer.Dispose(); } - - public static FirebaseTokenFactory Create(FirebaseApp app) - { - ISigner signer = null; - var serviceAccount = app.Options.Credential.ToServiceAccountCredential(); - if (serviceAccount != null) - { - // If the app was initialized with a service account, use it to sign - // tokens locally. - signer = new ServiceAccountSigner(serviceAccount); - } - else if (string.IsNullOrEmpty(app.Options.ServiceAccountId)) - { - // If no service account ID is specified, attempt to discover one and invoke the - // IAM service with it. - signer = new IAMSigner(new HttpClientFactory(), app.Options.Credential); - } - else - { - // If a service account ID is specified, invoke the IAM service with it. - signer = new FixedAccountIAMSigner( - new HttpClientFactory(), app.Options.Credential, app.Options.ServiceAccountId); - } - return new FirebaseTokenFactory(signer, SystemClock.Default); - } } internal class CustomTokenPayload: JsonWebToken.Payload diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenVerifier.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenVerifier.cs index e96b3349..be1704d8 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenVerifier.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenVerifier.cs @@ -15,6 +15,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Security.Cryptography; using System.Text; @@ -43,7 +44,6 @@ internal sealed class FirebaseTokenVerifier private static readonly IReadOnlyList StandardClaims = ImmutableList.Create("iss", "aud", "exp", "iat", "sub", "uid"); - public string ProjectId { get; } private readonly string _shortName; private readonly string _articledShortName; private readonly string _operation; @@ -52,7 +52,7 @@ internal sealed class FirebaseTokenVerifier private readonly IClock _clock; private readonly IPublicKeySource _keySource; - public FirebaseTokenVerifier(FirebaseTokenVerifierArgs args) + internal FirebaseTokenVerifier(FirebaseTokenVerifierArgs args) { ProjectId = args.ProjectId.ThrowIfNullOrEmpty(nameof(args.ProjectId)); _shortName = args.ShortName.ThrowIfNullOrEmpty(nameof(args.ShortName)); @@ -71,7 +71,9 @@ public FirebaseTokenVerifier(FirebaseTokenVerifierArgs args) } } - public async Task VerifyTokenAsync( + public string ProjectId { get; } + + internal async Task VerifyTokenAsync( string token, CancellationToken cancellationToken = default(CancellationToken)) { if (string.IsNullOrEmpty(token)) @@ -94,7 +96,7 @@ public async Task VerifyTokenAsync( string error = null; if (string.IsNullOrEmpty(header.KeyId)) { - if (FirebaseAudience == payload.Audience) + if (payload.Audience == FirebaseAudience) { error = $"{_operation} expects {_articledShortName}, but was given a custom " + "token."; @@ -140,7 +142,7 @@ public async Task VerifyTokenAsync( { error = $"Firebase {_shortName} has a subject claim longer than 128 characters."; } - + if (error != null) { throw new FirebaseException(error); @@ -162,6 +164,7 @@ await VerifySignatureAsync(segments, header.KeyId, cancellationToken) /// Verifies the integrity of a JWT by validating its signature. The JWT must be specified /// as an array of three segments (header, body and signature). /// + [SuppressMessage("StyleCop.Analyzers", "SA1009:ClosingParenthesisMustBeSpacedCorrectly", Justification = "Use of directives.")] private async Task VerifySignatureAsync( string[] segments, string keyId, CancellationToken cancellationToken) { @@ -179,7 +182,7 @@ private async Task VerifySignatureAsync( key.Id == keyId && key.RSA.VerifyHash( hash, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1) #elif NET45 - key.Id == keyId && + key.Id == keyId && ((RSACryptoServiceProvider) key.RSA).VerifyHash(hash, Sha256Oid, signature) #else #error Unsupported target @@ -218,11 +221,17 @@ internal static FirebaseTokenVerifier CreateIDTokenVerifier(FirebaseApp app) internal sealed class FirebaseTokenVerifierArgs { public string ProjectId { get; set; } + public string ShortName { get; set; } + public string Operation { get; set; } + public string Url { get; set; } + public string Issuer { get; set; } + public IClock Clock { get; set; } + public IPublicKeySource PublicKeySource { get; set; } } } diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/HttpPublicKeySource.cs b/FirebaseAdmin/FirebaseAdmin/Auth/HttpPublicKeySource.cs index ffbbd9ff..ec9269ca 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/HttpPublicKeySource.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/HttpPublicKeySource.cs @@ -48,12 +48,12 @@ internal sealed class HttpPublicKeySource: IPublicKeySource // pre-emptively refreshed instead of waiting until the last second. private static readonly TimeSpan ClockSkew = new TimeSpan(hours: 0, minutes: 5, seconds: 0); - private readonly string _certUrl; - private IReadOnlyList _cachedKeys; - private DateTime _expirationTime; private readonly SemaphoreSlim _lock = new SemaphoreSlim(1, 1); + private readonly string _certUrl; private readonly IClock _clock; private readonly HttpClientFactory _clientFactory; + private DateTime _expirationTime; + private IReadOnlyList _cachedKeys; public HttpPublicKeySource(string certUrl, IClock clock, HttpClientFactory clientFactory) { diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/IAMSigner.cs b/FirebaseAdmin/FirebaseAdmin/Auth/IAMSigner.cs index dec55cd4..6bc627b1 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/IAMSigner.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/IAMSigner.cs @@ -36,7 +36,8 @@ internal class IAMSigner : ISigner { private const string SignBlobUrl = "https://iam.googleapis.com/v1/projects/-/serviceAccounts/{0}:signBlob"; - private const string MetadataServerUrl = + + private const string MetadataServerUrl = "http://metadata/computeMetadata/v1/instance/service-accounts/default/email"; private readonly ConfigurableHttpClient _httpClient; @@ -86,11 +87,14 @@ private void ThrowIfError(HttpResponseMessage response, string content) var result = NewtonsoftJsonSerializer.Instance.Deserialize(content); error = result?.Error.Message; } - catch (Exception) {} // Ignore any errors encountered while parsing the originl error. + catch (Exception) + { + // Ignore any errors encountered while parsing the originl error. + } if (string.IsNullOrEmpty(error)) { error = "Response status code does not indicate success: " - + $"{(int) response.StatusCode} ({response.StatusCode})" + + $"{(int)response.StatusCode} ({response.StatusCode})" + $"{Environment.NewLine}{content}"; } throw new FirebaseException(error); @@ -175,8 +179,9 @@ internal sealed class FixedAccountIAMSigner : IAMSigner { private readonly string _keyId; - public FixedAccountIAMSigner(HttpClientFactory clientFactory, GoogleCredential credential, - string keyId): base(clientFactory, credential) + public FixedAccountIAMSigner( + HttpClientFactory clientFactory, GoogleCredential credential, string keyId) + : base(clientFactory, credential) { _keyId = keyId.ThrowIfNullOrEmpty(nameof(keyId)); } diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/ISigner.cs b/FirebaseAdmin/FirebaseAdmin/Auth/ISigner.cs index 2d63798e..dcacb8ee 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/ISigner.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/ISigner.cs @@ -22,7 +22,7 @@ namespace FirebaseAdmin.Auth /// Represents an object can be used to cryptographically sign data. Mainly used for signing /// custom JWT tokens issued to Firebase users. /// - internal interface ISigner: IDisposable + internal interface ISigner : IDisposable { /// /// Returns the ID (client email) of the service account used to sign payloads. diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/JwtUtils.cs b/FirebaseAdmin/FirebaseAdmin/Auth/JwtUtils.cs index 7fb5ab74..8fc8f9ec 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/JwtUtils.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/JwtUtils.cs @@ -50,13 +50,13 @@ private static string UrlSafeBase64Encode(byte[] bytes) return base64Value.TrimEnd('=').Replace('+', '-').Replace('/', '_'); } - public static string Base64Decode(string input) + internal static string Base64Decode(string input) { var raw = Base64DecodeToBytes(input); return Encoding.UTF8.GetString(raw); } - public static byte[] Base64DecodeToBytes(string input) + internal static byte[] Base64DecodeToBytes(string input) { // undo the url safe replacements input = input.Replace('-', '+').Replace('_', '/'); @@ -68,8 +68,10 @@ public static byte[] Base64DecodeToBytes(string input) return Convert.FromBase64String(input); } - public static async Task CreateSignedJwtAsync( - object header, object payload, ISigner signer, + internal static async Task CreateSignedJwtAsync( + object header, + object payload, + ISigner signer, CancellationToken cancellationToken = default(CancellationToken)) { string encodedHeader = Encode(header); diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/PublicKey.cs b/FirebaseAdmin/FirebaseAdmin/Auth/PublicKey.cs index e1779633..a29f05a4 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/PublicKey.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/PublicKey.cs @@ -27,6 +27,12 @@ namespace FirebaseAdmin.Auth /// internal sealed class PublicKey { + public PublicKey(string keyId, RSAKey rsa) + { + Id = keyId; + RSA = rsa; + } + /// /// The unique identifier of this key. /// @@ -37,11 +43,5 @@ internal sealed class PublicKey /// the public key. /// public RSAKey RSA { get; } - - public PublicKey(string keyId, RSAKey rsa) - { - Id = keyId; - RSA = rsa; - } } } diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/ServiceAccountSigner.cs b/FirebaseAdmin/FirebaseAdmin/Auth/ServiceAccountSigner.cs index adfc064d..ddd2614b 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/ServiceAccountSigner.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/ServiceAccountSigner.cs @@ -23,7 +23,7 @@ namespace FirebaseAdmin.Auth /// An implementation that uses service account credentials to sign /// data. Uses the private key present in the credential to produce signatures. /// - internal sealed class ServiceAccountSigner: ISigner + internal sealed class ServiceAccountSigner : ISigner { private readonly ServiceAccountCredential _credential; @@ -48,6 +48,6 @@ public ServiceAccountSigner(ServiceAccountCredential credential) return Task.FromResult(Convert.FromBase64String(signature)); } - public void Dispose() {} + public void Dispose() { } } } diff --git a/FirebaseAdmin/FirebaseAdmin/Extensions.cs b/FirebaseAdmin/FirebaseAdmin/Extensions.cs index db5a2a02..b8a1d960 100644 --- a/FirebaseAdmin/FirebaseAdmin/Extensions.cs +++ b/FirebaseAdmin/FirebaseAdmin/Extensions.cs @@ -38,7 +38,7 @@ public static ServiceAccountCredential ToServiceAccountCredential( { if (credential.UnderlyingCredential is GoogleCredential) { - return ((GoogleCredential) credential.UnderlyingCredential) + return ((GoogleCredential)credential.UnderlyingCredential) .ToServiceAccountCredential(); } return credential.UnderlyingCredential as ServiceAccountCredential; @@ -47,7 +47,7 @@ public static ServiceAccountCredential ToServiceAccountCredential( /// /// Creates a default (unauthenticated) from the /// factory. - /// + /// public static ConfigurableHttpClient CreateDefaultHttpClient( this HttpClientFactory clientFactory) { @@ -83,7 +83,8 @@ public static async Task PostJsonAsync( /// public static long UnixTimestamp(this IClock clock) { - return (long) (clock.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds; + var timeSinceEpoch = clock.UtcNow.Subtract(new DateTime(1970, 1, 1)); + return (long)timeSinceEpoch.TotalSeconds; } } } diff --git a/FirebaseAdmin/FirebaseAdmin/FirebaseAdmin.csproj b/FirebaseAdmin/FirebaseAdmin/FirebaseAdmin.csproj index b4af550e..c285ce46 100644 --- a/FirebaseAdmin/FirebaseAdmin/FirebaseAdmin.csproj +++ b/FirebaseAdmin/FirebaseAdmin/FirebaseAdmin.csproj @@ -21,11 +21,13 @@ https://github.com/Firebase/firebase-admin-dotnet git https://github.com/Firebase/firebase-admin-dotnet + ../../stylecop.ruleset + diff --git a/FirebaseAdmin/FirebaseAdmin/FirebaseApp.cs b/FirebaseAdmin/FirebaseAdmin/FirebaseApp.cs index 0c06aed3..aeafabe3 100644 --- a/FirebaseAdmin/FirebaseAdmin/FirebaseApp.cs +++ b/FirebaseAdmin/FirebaseAdmin/FirebaseApp.cs @@ -27,9 +27,10 @@ "3003684e85e61cf15f13150008c81f0b75a252673028e530ea95d0c581378da8c6846526ab9597"+ "4c6d0bc66d2462b51af69968a0e25114bde8811e0d6ee1dc22d4a59eee6a8bba4712cba839652f"+ "badddb9c")] -namespace FirebaseAdmin +namespace FirebaseAdmin { - internal delegate TResult ServiceFactory() where TResult: IFirebaseService; + internal delegate TResult ServiceFactory() + where TResult : IFirebaseService; /// /// This is the entry point to the Firebase Admin SDK. It holds configuration and state common @@ -43,52 +44,26 @@ public sealed class FirebaseApp private const string DefaultAppName = "[DEFAULT]"; internal static readonly IReadOnlyList DefaultScopes = ImmutableList.Create( - // Enables access to Firebase Realtime Database. - "https://www.googleapis.com/auth/firebase", - - // Enables access to the email address associated with a project. - "https://www.googleapis.com/auth/userinfo.email", - - // Enables access to Google Identity Toolkit (for user management APIs). - "https://www.googleapis.com/auth/identitytoolkit", - - // Enables access to Google Cloud Storage. - "https://www.googleapis.com/auth/devstorage.full_control", - - // Enables access to Google Cloud Firestore - "https://www.googleapis.com/auth/cloud-platform", - "https://www.googleapis.com/auth/datastore" - ); + "https://www.googleapis.com/auth/firebase", // RTDB. + "https://www.googleapis.com/auth/userinfo.email", // RTDB + "https://www.googleapis.com/auth/identitytoolkit", // User management + "https://www.googleapis.com/auth/devstorage.full_control", // Cloud Storage + "https://www.googleapis.com/auth/cloud-platform", // Cloud Firestore + "https://www.googleapis.com/auth/datastore"); private static readonly Dictionary Apps = new Dictionary(); private static readonly ILogger Logger = ApplicationContext.Logger.ForType(); // Guards the mutable state local to an app instance. - private readonly Object _lock = new Object(); - private bool _deleted = false; + private readonly object _lock = new object(); private readonly AppOptions _options; - /// - /// A copy of the this app was created with. - /// - public AppOptions Options - { - get - { - return new AppOptions(_options); - } - } - - /// - /// Name of this app. - /// - public string Name { get; } - // A collection of stateful services initialized using this app instance (e.g. // FirebaseAuth). Services are tracked here so they can be cleaned up when the app is // deleted. private readonly Dictionary _services = new Dictionary(); + private bool _deleted = false; private FirebaseApp(AppOptions options, string name) { @@ -104,6 +79,34 @@ private FirebaseApp(AppOptions options, string name) Name = name; } + /// + /// The default app instance. This property is null if the default app instance + /// doesn't yet exist. + /// + public static FirebaseApp DefaultInstance + { + get + { + return GetInstance(DefaultAppName); + } + } + + /// + /// A copy of the this app was created with. + /// + public AppOptions Options + { + get + { + return new AppOptions(_options); + } + } + + /// + /// Name of this app. + /// + public string Name { get; } + /// /// Deletes this app instance and cleans up any state associated with it. Once an app has /// been deleted, accessing any services related to it will result in an exception. @@ -135,7 +138,8 @@ public void Delete() } } - internal T GetOrInit(string id, ServiceFactory initializer) where T : class, IFirebaseService + internal T GetOrInit(string id, ServiceFactory initializer) + where T : class, IFirebaseService { lock (_lock) { @@ -147,12 +151,20 @@ internal T GetOrInit(string id, ServiceFactory initializer) where T : clas if (!_services.TryGetValue(id, out service)) { service = initializer(); - _services.Add(id, service); + _services.Add(id, service); } - return (T) service; + return (T)service; } } + /// + /// Returns the Google Cloud Platform project ID associated with this Firebase app. If a + /// project ID is specified in , that value is returned. If not + /// attempts to determine a project ID from the used to + /// initialize the app. Looks up the GOOGLE_CLOUD_PROJECT environment variable when all + /// else fails. + /// + /// A project ID string or null. internal string GetProjectId() { if (!string.IsNullOrEmpty(Options.ProjectId)) @@ -160,14 +172,14 @@ internal string GetProjectId() return Options.ProjectId; } var projectId = Options.Credential.ToServiceAccountCredential()?.ProjectId; - if (!String.IsNullOrEmpty(projectId)) + if (!string.IsNullOrEmpty(projectId)) { return projectId; } - foreach (var variableName in new [] {"GOOGLE_CLOUD_PROJECT", "GCLOUD_PROJECT"}) + foreach (var variableName in new[] { "GOOGLE_CLOUD_PROJECT", "GCLOUD_PROJECT" }) { projectId = Environment.GetEnvironmentVariable(variableName); - if (!String.IsNullOrEmpty(projectId)) + if (!string.IsNullOrEmpty(projectId)) { return projectId; } @@ -235,7 +247,7 @@ public static FirebaseApp Create(AppOptions options, string name) { throw new ArgumentException("The default FirebaseApp already exists."); } - else + else { throw new ArgumentException($"FirebaseApp named {name} already exists."); } @@ -254,18 +266,6 @@ private static AppOptions GetOptionsFromEnvironment() }; } - /// - /// The default app instance. This property is null if the default app instance - /// doesn't yet exist. - /// - public static FirebaseApp DefaultInstance - { - get - { - return GetInstance(DefaultAppName); - } - } - /// /// Returns the app instance identified by the given name. /// @@ -279,13 +279,13 @@ public static FirebaseApp GetInstance(string name) { throw new ArgumentException("App name to lookup must not be null or empty"); } - lock (Apps) + lock (Apps) { FirebaseApp app; if (Apps.TryGetValue(name, out app)) { return app; - } + } } return null; } @@ -306,7 +306,7 @@ internal static void DeleteAll() { throw new InvalidOperationException("Failed to delete all apps"); } - } + } } } } diff --git a/FirebaseAdmin/FirebaseAdmin/FirebaseException.cs b/FirebaseAdmin/FirebaseAdmin/FirebaseException.cs index a2032d0a..e2a52733 100644 --- a/FirebaseAdmin/FirebaseAdmin/FirebaseException.cs +++ b/FirebaseAdmin/FirebaseAdmin/FirebaseException.cs @@ -19,10 +19,12 @@ namespace FirebaseAdmin /// /// Common error type for all exceptions raised by Firebase APIs. /// - public sealed class FirebaseException: Exception + public sealed class FirebaseException : Exception { - internal FirebaseException(string message): base(message) {} - - internal FirebaseException(string message, Exception inner): base(message, inner) {} + internal FirebaseException(string message) + : base(message) { } + + internal FirebaseException(string message, Exception inner) + : base(message, inner) { } } } diff --git a/stylecop.ruleset b/stylecop.ruleset new file mode 100644 index 00000000..b1c65323 --- /dev/null +++ b/stylecop.ruleset @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From ed910d525b13b13532d9374c6bf079f953c19456 Mon Sep 17 00:00:00 2001 From: hiranya911 Date: Mon, 21 Jan 2019 00:56:39 -0800 Subject: [PATCH 02/13] Added stylecop to tests --- .../Auth/FirebaseAuthTest.cs | 24 ++-- .../Auth/FirebaseTokenFactoryTest.cs | 15 +-- .../Auth/FirebaseTokenVerifierTest.cs | 37 +++--- .../Auth/HttpPublicKeySourceTest.cs | 2 +- .../FirebaseAdmin.Tests/Auth/IAMSignerTest.cs | 106 +++++++++--------- .../Auth/ServiceAccountSignerTest.cs | 4 +- .../FirebaseAdmin.Tests.csproj | 6 + .../FirebaseAdmin.Tests/FirebaseAppTest.cs | 19 ++-- .../FirebaseAdmin.Tests/MockClock.cs | 17 +-- .../FirebaseAdmin.Tests/MockMessageHandler.cs | 97 ++++++++-------- .../FirebaseAdmin/FirebaseAdmin.csproj | 4 +- stylecop_test.ruleset | 31 +++++ 12 files changed, 204 insertions(+), 158 deletions(-) create mode 100644 stylecop_test.ruleset diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseAuthTest.cs b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseAuthTest.cs index 97a4c1f1..40983e00 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseAuthTest.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseAuthTest.cs @@ -30,7 +30,7 @@ namespace FirebaseAdmin.Auth.Tests { public class FirebaseAuthTest: IDisposable { - private static readonly GoogleCredential mockCredential = + private static readonly GoogleCredential MockCredential = GoogleCredential.FromAccessToken("test-token"); [Fact] @@ -42,7 +42,7 @@ public void GetAuthWithoutApp() [Fact] public void GetDefaultAuth() { - var app = FirebaseApp.Create(new AppOptions(){Credential = mockCredential}); + var app = FirebaseApp.Create(new AppOptions() { Credential = MockCredential }); FirebaseAuth auth = FirebaseAuth.DefaultInstance; Assert.Same(auth, FirebaseAuth.DefaultInstance); app.Delete(); @@ -52,7 +52,7 @@ public void GetDefaultAuth() [Fact] public void GetAuth() { - var app = FirebaseApp.Create(new AppOptions(){Credential = mockCredential}, "MyApp"); + var app = FirebaseApp.Create(new AppOptions() { Credential = MockCredential }, "MyApp"); FirebaseAuth auth = FirebaseAuth.GetAuth(app); Assert.Same(auth, FirebaseAuth.GetAuth(app)); app.Delete(); @@ -62,7 +62,7 @@ public void GetAuth() [Fact] public async Task UseAfterDelete() { - var app = FirebaseApp.Create(new AppOptions(){Credential = mockCredential}); + var app = FirebaseApp.Create(new AppOptions() { Credential = MockCredential }); FirebaseAuth auth = FirebaseAuth.DefaultInstance; app.Delete(); await Assert.ThrowsAsync( @@ -75,7 +75,7 @@ await Assert.ThrowsAsync( public async Task CreateCustomToken() { var cred = GoogleCredential.FromFile("./resources/service_account.json"); - FirebaseApp.Create(new AppOptions(){Credential = cred}); + FirebaseApp.Create(new AppOptions() { Credential = cred }); var token = await FirebaseAuth.DefaultInstance.CreateCustomTokenAsync("user1"); VerifyCustomToken(token, "user1", null); } @@ -84,7 +84,7 @@ public async Task CreateCustomToken() public async Task CreateCustomTokenWithClaims() { var cred = GoogleCredential.FromFile("./resources/service_account.json"); - FirebaseApp.Create(new AppOptions(){Credential = cred}); + FirebaseApp.Create(new AppOptions() { Credential = cred }); var developerClaims = new Dictionary() { {"admin", true}, @@ -100,7 +100,7 @@ public async Task CreateCustomTokenWithClaims() public async Task CreateCustomTokenCancel() { var cred = GoogleCredential.FromFile("./resources/service_account.json"); - FirebaseApp.Create(new AppOptions(){Credential = cred}); + FirebaseApp.Create(new AppOptions() { Credential = cred }); var canceller = new CancellationTokenSource(); canceller.Cancel(); await Assert.ThrowsAsync( @@ -111,7 +111,7 @@ await Assert.ThrowsAsync( [Fact] public async Task CreateCustomTokenInvalidCredential() { - FirebaseApp.Create(new AppOptions(){Credential = mockCredential}); + FirebaseApp.Create(new AppOptions() { Credential = MockCredential }); await Assert.ThrowsAsync( async () => await FirebaseAuth.DefaultInstance.CreateCustomTokenAsync("user1")); } @@ -119,7 +119,7 @@ await Assert.ThrowsAsync( [Fact] public async Task VerifyIdTokenNoProjectId() { - FirebaseApp.Create(new AppOptions(){Credential = mockCredential}); + FirebaseApp.Create(new AppOptions() { Credential = MockCredential }); var idToken = await FirebaseTokenVerifierTest.CreateTestTokenAsync(); await Assert.ThrowsAsync( async () => await FirebaseAuth.DefaultInstance.VerifyIdTokenAsync(idToken)); @@ -130,7 +130,7 @@ public async Task VerifyIdTokenCancel() { FirebaseApp.Create(new AppOptions() { - Credential = mockCredential, + Credential = MockCredential, ProjectId = "test-project", }); var canceller = new CancellationTokenSource(); @@ -143,7 +143,7 @@ await Assert.ThrowsAnyAsync( private static void VerifyCustomToken(string token, string uid, Dictionary claims) { - String[] segments = token.Split("."); + string[] segments = token.Split("."); Assert.Equal(3, segments.Length); var payload = JwtUtils.Decode(segments[1]); @@ -166,7 +166,7 @@ private static void VerifyCustomToken(string token, string uid, Dictionary( async () => await factory.CreateCustomTokenAsync(null)); await Assert.ThrowsAsync( - async () => await factory.CreateCustomTokenAsync("")); + async () => await factory.CreateCustomTokenAsync(string.Empty)); await Assert.ThrowsAsync( - async () => await factory.CreateCustomTokenAsync(new String('a', 129))); + async () => await factory.CreateCustomTokenAsync(new string('a', 129))); } [Fact] public async Task ReservedClaims() { var factory = new FirebaseTokenFactory(new MockSigner(), new MockClock()); - foreach(var key in FirebaseTokenFactory.ReservedClaims) + foreach (var key in FirebaseTokenFactory.ReservedClaims) { - var developerClaims = new Dictionary(){ + var developerClaims = new Dictionary() + { {key, "value"}, }; await Assert.ThrowsAsync( - async () => await factory.CreateCustomTokenAsync("user", developerClaims)); - } + async () => await factory.CreateCustomTokenAsync("user", developerClaims)); + } } private static void VerifyCustomToken( string token, string uid, Dictionary claims) { - String[] segments = token.Split("."); + string[] segments = token.Split("."); Assert.Equal(3, segments.Length); // verify header var header = JwtUtils.Decode(segments[0]); diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseTokenVerifierTest.cs b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseTokenVerifierTest.cs index f8bfea99..b1c55f79 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseTokenVerifierTest.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseTokenVerifierTest.cs @@ -32,8 +32,11 @@ public class FirebaseTokenVerifierTest: IDisposable { private static readonly IPublicKeySource KeySource = new FileSystemPublicKeySource( "./resources/public_cert.pem"); + private static readonly IClock Clock = new MockClock(); + private static readonly ISigner Signer = CreateTestSigner(); + private static readonly FirebaseTokenVerifier TokenVerifier = new FirebaseTokenVerifier( new FirebaseTokenVerifierArgs() { @@ -46,7 +49,7 @@ public class FirebaseTokenVerifierTest: IDisposable PublicKeySource = KeySource, }); - private static readonly GoogleCredential mockCredential = + private static readonly GoogleCredential MockCredential = GoogleCredential.FromAccessToken("test-token"); [Fact] @@ -63,8 +66,8 @@ public async Task ValidToken() Assert.Equal("testuser", decoded.Subject); // The default test token created by CreateTestTokenAsync has an issue time 10 minutes // ago, and an expiry time 50 minutes in the future. - Assert.Equal(Clock.UnixTimestamp() - 60 * 10, decoded.IssuedAtTimeSeconds); - Assert.Equal(Clock.UnixTimestamp() + 60 * 50, decoded.ExpirationTimeSeconds); + Assert.Equal(Clock.UnixTimestamp() - (60 * 10), decoded.IssuedAtTimeSeconds); + Assert.Equal(Clock.UnixTimestamp() + (60 * 50), decoded.ExpirationTimeSeconds); Assert.Single(decoded.Claims); object value; Assert.True(decoded.Claims.TryGetValue("foo", out value)); @@ -77,7 +80,7 @@ public async Task InvalidArgument() await Assert.ThrowsAsync( async () => await TokenVerifier.VerifyTokenAsync(null)); await Assert.ThrowsAsync( - async () => await TokenVerifier.VerifyTokenAsync("")); + async () => await TokenVerifier.VerifyTokenAsync(string.Empty)); } [Fact] @@ -92,7 +95,7 @@ public async Task NoKid() { var header = new Dictionary() { - {"kid", ""}, + {"kid", string.Empty}, }; var idToken = await CreateTestTokenAsync(headerOverrides: header); await Assert.ThrowsAsync( @@ -176,7 +179,7 @@ public async Task EmptySubject() { var payload = new Dictionary() { - {"sub", ""}, + {"sub", string.Empty}, }; var idToken = await CreateTestTokenAsync(payloadOverrides: payload); await Assert.ThrowsAsync( @@ -188,7 +191,7 @@ public async Task LongSubject() { var payload = new Dictionary() { - {"sub", new String('a', 129)}, + { "sub", new string('a', 129) }, }; var idToken = await CreateTestTokenAsync(payloadOverrides: payload); await Assert.ThrowsAsync( @@ -200,7 +203,7 @@ public void ProjectIdFromOptions() { var app = FirebaseApp.Create(new AppOptions() { - Credential = mockCredential, + Credential = MockCredential, ProjectId = "explicit-project-id", }); var verifier = FirebaseTokenVerifier.CreateIDTokenVerifier(app); @@ -226,14 +229,14 @@ public void ProjectIdFromEnvironment() { var app = FirebaseApp.Create(new AppOptions() { - Credential = mockCredential, + Credential = MockCredential, }); var verifier = FirebaseTokenVerifier.CreateIDTokenVerifier(app); Assert.Equal("env-project-id", verifier.ProjectId); } finally { - Environment.SetEnvironmentVariable("GOOGLE_CLOUD_PROJECT", ""); + Environment.SetEnvironmentVariable("GOOGLE_CLOUD_PROJECT", string.Empty); } } @@ -267,11 +270,11 @@ internal static async Task CreateTestTokenAsync( var payload = new Dictionary() { - {"sub", "testuser"}, - {"iss", "https://securetoken.google.com/test-project"}, - {"aud", "test-project"}, - {"iat", Clock.UnixTimestamp() - 60 * 10}, - {"exp", Clock.UnixTimestamp() + 60 * 50}, + { "sub", "testuser" }, + { "iss", "https://securetoken.google.com/test-project" }, + { "aud", "test-project" }, + { "iat", Clock.UnixTimestamp() - (60 * 10) }, + { "exp", Clock.UnixTimestamp() + (60 * 50) }, }; if (payloadOverrides != null) { @@ -286,7 +289,7 @@ internal static async Task CreateTestTokenAsync( private static ISigner CreateTestSigner() { var credential = GoogleCredential.FromFile("./resources/service_account.json"); - var serviceAccount = (ServiceAccountCredential) credential.UnderlyingCredential; + var serviceAccount = (ServiceAccountCredential)credential.UnderlyingCredential; return new ServiceAccountSigner(serviceAccount); } } @@ -298,7 +301,7 @@ internal class FileSystemPublicKeySource : IPublicKeySource public FileSystemPublicKeySource(string file) { var x509cert = new X509Certificate2(File.ReadAllBytes(file)); - var rsa = (RSA) x509cert.PublicKey.Key; + var rsa = (RSA)x509cert.PublicKey.Key; _rsa = ImmutableList.Create(new PublicKey("test-key-id", rsa)); } diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/HttpPublicKeySourceTest.cs b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/HttpPublicKeySourceTest.cs index e7563010..1a53a4a0 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/HttpPublicKeySourceTest.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/HttpPublicKeySourceTest.cs @@ -92,7 +92,7 @@ public void InvalidArguments() Assert.Throws( () => new HttpPublicKeySource(null, clock, clientFactory)); Assert.Throws( - () => new HttpPublicKeySource("", clock, clientFactory)); + () => new HttpPublicKeySource(string.Empty, clock, clientFactory)); Assert.Throws( () => new HttpPublicKeySource("https://example.com/certs", null, clientFactory)); Assert.Throws( diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/IAMSignerTest.cs b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/IAMSignerTest.cs index 20815944..f454953b 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/IAMSignerTest.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/IAMSignerTest.cs @@ -27,6 +27,57 @@ namespace FirebaseAdmin.Auth.Tests { + public class IAMSignerTest + { + [Fact] + public async Task Signer() + { + var bytes = Encoding.UTF8.GetBytes("signature"); + var handler = new MockMessageHandler() + { + Response = "discovered-service-account", + }; + var factory = new MockHttpClientFactory(handler); + var signer = new IAMSigner(factory, GoogleCredential.FromAccessToken("token")); + Assert.Equal("discovered-service-account", await signer.GetKeyIdAsync()); + Assert.Equal(1, handler.Calls); + + // should only fetch account once + Assert.Equal("discovered-service-account", await signer.GetKeyIdAsync()); + Assert.Equal(1, handler.Calls); + + handler.Response = new SignBlobResponse() + { + Signature = Convert.ToBase64String(bytes), + }; + byte[] data = Encoding.UTF8.GetBytes("Hello world"); + byte[] signature = await signer.SignDataAsync(data); + Assert.Equal(bytes, signature); + var req = NewtonsoftJsonSerializer.Instance.Deserialize( + handler.Request); + Assert.Equal(Convert.ToBase64String(data), req.BytesToSign); + Assert.Equal(2, handler.Calls); + } + + [Fact] + public async Task AccountDiscoveryError() + { + var bytes = Encoding.UTF8.GetBytes("signature"); + var handler = new MockMessageHandler() + { + StatusCode = HttpStatusCode.InternalServerError, + }; + var factory = new MockHttpClientFactory(handler); + var signer = new IAMSigner(factory, GoogleCredential.FromAccessToken("token")); + await Assert.ThrowsAsync( + async () => await signer.GetKeyIdAsync()); + Assert.Equal(1, handler.Calls); + await Assert.ThrowsAsync( + async () => await signer.GetKeyIdAsync()); + Assert.Equal(1, handler.Calls); + } + } + public class FixedAccountIAMSignerTest { [Fact] @@ -59,7 +110,7 @@ public async Task WelformedSignError() var handler = new MockMessageHandler() { StatusCode = HttpStatusCode.InternalServerError, - Response = @"{""error"": {""message"": ""test reason""}}" + Response = @"{""error"": {""message"": ""test reason""}}", }; var factory = new MockHttpClientFactory(handler); var signer = new FixedAccountIAMSigner( @@ -77,7 +128,7 @@ public async Task UnexpectedSignError() var handler = new MockMessageHandler() { StatusCode = HttpStatusCode.InternalServerError, - Response = "not json" + Response = "not json", }; var factory = new MockHttpClientFactory(handler); var signer = new FixedAccountIAMSigner( @@ -89,55 +140,4 @@ public async Task UnexpectedSignError() Assert.Contains("not json", ex.Message); } } - - public class IAMSignerTest - { - [Fact] - public async Task Signer() - { - var bytes = Encoding.UTF8.GetBytes("signature"); - var handler = new MockMessageHandler() - { - Response = "discovered-service-account", - }; - var factory = new MockHttpClientFactory(handler); - var signer = new IAMSigner(factory, GoogleCredential.FromAccessToken("token")); - Assert.Equal("discovered-service-account", await signer.GetKeyIdAsync()); - Assert.Equal(1, handler.Calls); - - // should only fetch account once - Assert.Equal("discovered-service-account", await signer.GetKeyIdAsync()); - Assert.Equal(1, handler.Calls); - - handler.Response = new SignBlobResponse() - { - Signature = Convert.ToBase64String(bytes), - }; - byte[] data = Encoding.UTF8.GetBytes("Hello world"); - byte[] signature = await signer.SignDataAsync(data); - Assert.Equal(bytes, signature); - var req = NewtonsoftJsonSerializer.Instance.Deserialize( - handler.Request); - Assert.Equal(Convert.ToBase64String(data), req.BytesToSign); - Assert.Equal(2, handler.Calls); - } - - [Fact] - public async Task AccountDiscoveryError() - { - var bytes = Encoding.UTF8.GetBytes("signature"); - var handler = new MockMessageHandler() - { - StatusCode = HttpStatusCode.InternalServerError, - }; - var factory = new MockHttpClientFactory(handler); - var signer = new IAMSigner(factory, GoogleCredential.FromAccessToken("token")); - await Assert.ThrowsAsync( - async () => await signer.GetKeyIdAsync()); - Assert.Equal(1, handler.Calls); - await Assert.ThrowsAsync( - async () => await signer.GetKeyIdAsync()); - Assert.Equal(1, handler.Calls); - } - } } diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/ServiceAccountSignerTest.cs b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/ServiceAccountSignerTest.cs index 2874a79f..8b0811b8 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/ServiceAccountSignerTest.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/ServiceAccountSignerTest.cs @@ -30,7 +30,7 @@ public class ServiceAccountSignerTest public async Task Signer() { var credential = GoogleCredential.FromFile("./resources/service_account.json"); - var serviceAccount = (ServiceAccountCredential) credential.UnderlyingCredential; + var serviceAccount = (ServiceAccountCredential)credential.UnderlyingCredential; var signer = new ServiceAccountSigner(serviceAccount); Assert.Equal("client@test-project.iam.gserviceaccount.com", await signer.GetKeyIdAsync()); @@ -48,7 +48,7 @@ public void NullCredential() private bool Verify(byte[] data, byte[] signature) { var x509cert = new X509Certificate2(File.ReadAllBytes("./resources/public_cert.pem")); - var rsa = (RSA) x509cert.PublicKey.Key; + var rsa = (RSA)x509cert.PublicKey.Key; return rsa.VerifyData( data, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); } diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/FirebaseAdmin.Tests.csproj b/FirebaseAdmin/FirebaseAdmin.Tests/FirebaseAdmin.Tests.csproj index fd4c9036..b936e804 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/FirebaseAdmin.Tests.csproj +++ b/FirebaseAdmin/FirebaseAdmin.Tests/FirebaseAdmin.Tests.csproj @@ -5,6 +5,9 @@ false ../../FirebaseAdmin.snk true + true + true + ../../stylecop_test.ruleset @@ -17,6 +20,9 @@ + + all + diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/FirebaseAppTest.cs b/FirebaseAdmin/FirebaseAdmin.Tests/FirebaseAppTest.cs index cc525acd..9268a6ee 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/FirebaseAppTest.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/FirebaseAppTest.cs @@ -96,7 +96,7 @@ public void CreateAppOptions() }; var app = FirebaseApp.Create(options); Assert.Equal("[DEFAULT]", app.Name); - + var copy = app.Options; Assert.NotSame(options, copy); Assert.Same(credential, copy.Credential); @@ -114,7 +114,7 @@ public void ServiceAccountCredentialScoping() }; var app = FirebaseApp.Create(options); Assert.Equal("[DEFAULT]", app.Name); - + var copy = app.Options; Assert.NotSame(options, copy); Assert.NotSame(credential, copy.Credential); @@ -139,7 +139,7 @@ public void ApplicationDefaultCredentials() } finally { - Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", ""); + Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", string.Empty); } } @@ -169,7 +169,7 @@ public void GetProjectIdFromServiceAccount() [Fact] public void GetProjectIdFromEnvironment() { - foreach (var name in new string[]{"GOOGLE_CLOUD_PROJECT", "GCLOUD_PROJECT"}) + foreach (var name in new string[] {"GOOGLE_CLOUD_PROJECT", "GCLOUD_PROJECT"}) { Environment.SetEnvironmentVariable(name, "env-project"); try @@ -180,7 +180,7 @@ public void GetProjectIdFromEnvironment() } finally { - Environment.SetEnvironmentVariable(name, ""); + Environment.SetEnvironmentVariable(name, string.Empty); } } } @@ -196,14 +196,15 @@ public void GetOrInitService() var service1 = app.GetOrInit("MockService", factory); var service2 = app.GetOrInit("MockService", factory); Assert.Same(service1, service2); - Assert.Throws(() => { + Assert.Throws(() => + { app.GetOrInit("MockService", () => { return new OtherMockService(); }); }); - + Assert.False(service1.Deleted); app.Delete(); Assert.True(service1.Deleted); - Assert.Throws(() => + Assert.Throws(() => { app.GetOrInit("MockService", factory); }); @@ -211,7 +212,7 @@ public void GetOrInitService() public void Dispose() { - FirebaseApp.DeleteAll(); + FirebaseApp.DeleteAll(); } } diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/MockClock.cs b/FirebaseAdmin/FirebaseAdmin.Tests/MockClock.cs index d4fb09e6..c68cf24e 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/MockClock.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/MockClock.cs @@ -19,15 +19,20 @@ namespace FirebaseAdmin.Tests { public class MockClock : IClock { + private object _lock = new object(); + private DateTime _utcNow; + + public MockClock() + { + Now = DateTime.Now; + } + public DateTime Now { get { return UtcNow.ToLocalTime(); } set { UtcNow = value.ToUniversalTime(); } } - private object _lock = new object(); - private DateTime _utcNow; - public DateTime UtcNow { get @@ -37,6 +42,7 @@ public DateTime UtcNow return _utcNow; } } + set { lock (_lock) @@ -45,10 +51,5 @@ public DateTime UtcNow } } } - - public MockClock() - { - Now = DateTime.Now; - } } } diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/MockMessageHandler.cs b/FirebaseAdmin/FirebaseAdmin.Tests/MockMessageHandler.cs index 7bc4e209..1feff6f7 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/MockMessageHandler.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/MockMessageHandler.cs @@ -26,65 +26,27 @@ namespace FirebaseAdmin.Tests { - internal class MockHttpClientFactory : HttpClientFactory - { - private HttpMessageHandler Handler { get; set; } - - public MockHttpClientFactory(HttpMessageHandler handler) - { - Handler = handler; - } - - protected override HttpMessageHandler CreateHandler(CreateHttpClientArgs args) - { - return Handler; - } - } - /// /// An implementation that counts the number of requests - /// processed. + /// and facilitates mocking HTTP interactions locally. /// - internal abstract class CountableMessageHandler : HttpMessageHandler + internal class MockMessageHandler : CountableMessageHandler { - private int _calls; - - public int Calls - { - get { return _calls; } - } - - sealed protected override Task SendAsync( - HttpRequestMessage request, CancellationToken cancellationToken) + public MockMessageHandler() { - Interlocked.Increment(ref _calls); - return SendAsyncCore(request, cancellationToken); + StatusCode = HttpStatusCode.OK; } - protected abstract Task SendAsyncCore( - HttpRequestMessage request, CancellationToken cancellationToken); - } + public delegate void SetHeaders(HttpResponseHeaders header); - /// - /// An implementation that counts the number of requests - /// and facilitates mocking HTTP interactions locally. - /// - internal class MockMessageHandler : CountableMessageHandler - { public string Request { get; private set; } - + public HttpStatusCode StatusCode { get; set; } - public Object Response { get; set; } - public delegate void SetHeaders(HttpResponseHeaders header); + public object Response { get; set; } public SetHeaders ApplyHeaders { get; set; } - public MockMessageHandler() - { - StatusCode = HttpStatusCode.OK; - } - protected override async Task SendAsyncCore( HttpRequestMessage request, CancellationToken cancellationToken) { @@ -95,7 +57,7 @@ protected override async Task SendAsyncCore( else { Request = null; - } + } var resp = new HttpResponseMessage(); string json; if (Response is byte[]) @@ -109,8 +71,8 @@ protected override async Task SendAsyncCore( else { json = NewtonsoftJsonSerializer.Instance.Serialize(Response); - } - resp.StatusCode = StatusCode; + } + resp.StatusCode = StatusCode; if (ApplyHeaders != null) { ApplyHeaders(resp.Headers); @@ -121,4 +83,43 @@ protected override async Task SendAsyncCore( return await tcs.Task; } } + + /// + /// An implementation that counts the number of requests + /// processed. + /// + internal abstract class CountableMessageHandler : HttpMessageHandler + { + private int _calls; + + public int Calls + { + get { return _calls; } + } + + protected sealed override Task SendAsync( + HttpRequestMessage request, CancellationToken cancellationToken) + { + Interlocked.Increment(ref _calls); + return SendAsyncCore(request, cancellationToken); + } + + protected abstract Task SendAsyncCore( + HttpRequestMessage request, CancellationToken cancellationToken); + } + + internal class MockHttpClientFactory : HttpClientFactory + { + private readonly HttpMessageHandler handler; + + public MockHttpClientFactory(HttpMessageHandler handler) + { + this.handler = handler; + } + + protected override HttpMessageHandler CreateHandler(CreateHttpClientArgs args) + { + return this.handler; + } + } } diff --git a/FirebaseAdmin/FirebaseAdmin/FirebaseAdmin.csproj b/FirebaseAdmin/FirebaseAdmin/FirebaseAdmin.csproj index c285ce46..117c7603 100644 --- a/FirebaseAdmin/FirebaseAdmin/FirebaseAdmin.csproj +++ b/FirebaseAdmin/FirebaseAdmin/FirebaseAdmin.csproj @@ -27,7 +27,9 @@ - + + all + diff --git a/stylecop_test.ruleset b/stylecop_test.ruleset new file mode 100644 index 00000000..6f7fe1ed --- /dev/null +++ b/stylecop_test.ruleset @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From fccf06ccd16250845429b5567a36c09a487ed5dc Mon Sep 17 00:00:00 2001 From: hiranya911 Date: Mon, 21 Jan 2019 14:49:04 -0800 Subject: [PATCH 03/13] Fixing more lint errors --- .../FirebaseAdmin.IntegrationTests.csproj | 7 ++++- .../FirebaseAuthTest.cs | 21 ++++++++------- .../IntegrationTestUtils.cs | 3 ++- .../Auth/FirebaseAuthTest.cs | 8 +++--- .../Auth/FirebaseTokenFactoryTest.cs | 10 +++---- .../Auth/FirebaseTokenVerifierTest.cs | 26 +++++++++---------- .../FirebaseAdmin.Tests.csproj | 6 ++--- .../FirebaseAdmin.Tests/FirebaseAppTest.cs | 10 +++---- FirebaseAdmin/FirebaseAdmin/AppOptions.cs | 2 +- .../FirebaseAdmin/Auth/FirebaseAuth.cs | 2 +- .../Auth/FirebaseTokenFactory.cs | 14 +++++----- .../Auth/FirebaseTokenVerifier.cs | 2 +- .../FirebaseAdmin/Auth/HttpPublicKeySource.cs | 2 +- FirebaseAdmin/FirebaseAdmin/FirebaseApp.cs | 10 +++---- stylecop.ruleset | 4 --- stylecop_test.ruleset | 4 --- 16 files changed, 65 insertions(+), 66 deletions(-) diff --git a/FirebaseAdmin/FirebaseAdmin.IntegrationTests/FirebaseAdmin.IntegrationTests.csproj b/FirebaseAdmin/FirebaseAdmin.IntegrationTests/FirebaseAdmin.IntegrationTests.csproj index c428e7b4..3edd66b0 100644 --- a/FirebaseAdmin/FirebaseAdmin.IntegrationTests/FirebaseAdmin.IntegrationTests.csproj +++ b/FirebaseAdmin/FirebaseAdmin.IntegrationTests/FirebaseAdmin.IntegrationTests.csproj @@ -2,8 +2,10 @@ netcoreapp2.0 - false + true + true + ../../stylecop_test.ruleset @@ -12,6 +14,9 @@ + + all + diff --git a/FirebaseAdmin/FirebaseAdmin.IntegrationTests/FirebaseAuthTest.cs b/FirebaseAdmin/FirebaseAdmin.IntegrationTests/FirebaseAuthTest.cs index 435f3f59..bf8a467e 100644 --- a/FirebaseAdmin/FirebaseAdmin.IntegrationTests/FirebaseAuthTest.cs +++ b/FirebaseAdmin/FirebaseAdmin.IntegrationTests/FirebaseAuthTest.cs @@ -27,14 +27,14 @@ namespace FirebaseAdmin.IntegrationTests { public class FirebaseAuthTest { - private const string VerifyCustomTokenUrl = + private const string VerifyCustomTokenUrl = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyCustomToken"; public FirebaseAuthTest() { IntegrationTestUtils.EnsureDefaultApp(); } - + [Fact] public async Task CreateCustomToken() { @@ -50,9 +50,9 @@ public async Task CreateCustomTokenWithClaims() { var developerClaims = new Dictionary() { - {"admin", true}, - {"package", "gold"}, - {"magicNumber", 42L}, + { "admin", true }, + { "package", "gold" }, + { "magicNumber", 42L }, }; var customToken = await FirebaseAuth.DefaultInstance.CreateCustomTokenAsync( "testuser", developerClaims); @@ -72,8 +72,8 @@ public async Task CreateCustomTokenWithClaims() public async Task CreateCustomTokenWithoutServiceAccount() { var googleCred = FirebaseApp.DefaultInstance.Options.Credential; - var serviceAcct = (ServiceAccountCredential) googleCred.UnderlyingCredential; - var token = await ((ITokenAccess) googleCred).GetAccessTokenForRequestAsync(); + var serviceAcct = (ServiceAccountCredential)googleCred.UnderlyingCredential; + var token = await ((ITokenAccess)googleCred).GetAccessTokenForRequestAsync(); var app = FirebaseApp.Create(new AppOptions() { Credential = GoogleCredential.FromAccessToken(token), @@ -98,12 +98,13 @@ private static async Task SignInWithCustomTokenAsync(string customToken) var rb = new Google.Apis.Requests.RequestBuilder() { Method = Google.Apis.Http.HttpConsts.Post, - BaseUri = new Uri(VerifyCustomTokenUrl), + BaseUri = new Uri(VerifyCustomTokenUrl), }; rb.AddParameter(RequestParameterType.Query, "key", IntegrationTestUtils.GetApiKey()); var request = rb.CreateRequest(); var jsonSerializer = Google.Apis.Json.NewtonsoftJsonSerializer.Instance; - var payload = jsonSerializer.Serialize(new SignInRequest{ + var payload = jsonSerializer.Serialize(new SignInRequest + { CustomToken = customToken, ReturnSecureToken = true, }); @@ -131,6 +132,6 @@ internal class SignInRequest internal class SignInResponse { [Newtonsoft.Json.JsonProperty("idToken")] - public String IdToken { get; set; } + public string IdToken { get; set; } } } diff --git a/FirebaseAdmin/FirebaseAdmin.IntegrationTests/IntegrationTestUtils.cs b/FirebaseAdmin/FirebaseAdmin.IntegrationTests/IntegrationTestUtils.cs index 5761de85..b2be8bff 100644 --- a/FirebaseAdmin/FirebaseAdmin.IntegrationTests/IntegrationTestUtils.cs +++ b/FirebaseAdmin/FirebaseAdmin.IntegrationTests/IntegrationTestUtils.cs @@ -26,7 +26,8 @@ internal static class IntegrationTestUtils private const string ServiceAccountFile = "./resources/integration_cert.json"; private const string ApiKeyFile = "./resources/integration_apikey.txt"; - private static readonly Lazy DefaultFirebaseApp = new Lazy(() => { + private static readonly Lazy DefaultFirebaseApp = new Lazy(() => + { var options = new AppOptions() { Credential = GoogleCredential.FromFile(ServiceAccountFile), diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseAuthTest.cs b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseAuthTest.cs index 40983e00..4df8974e 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseAuthTest.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseAuthTest.cs @@ -28,7 +28,7 @@ [assembly: CollectionBehavior(DisableTestParallelization = true)] namespace FirebaseAdmin.Auth.Tests { - public class FirebaseAuthTest: IDisposable + public class FirebaseAuthTest : IDisposable { private static readonly GoogleCredential MockCredential = GoogleCredential.FromAccessToken("test-token"); @@ -87,9 +87,9 @@ public async Task CreateCustomTokenWithClaims() FirebaseApp.Create(new AppOptions() { Credential = cred }); var developerClaims = new Dictionary() { - {"admin", true}, - {"package", "gold"}, - {"magicNumber", 42L}, + { "admin", true }, + { "package", "gold" }, + { "magicNumber", 42L }, }; var token = await FirebaseAuth.DefaultInstance.CreateCustomTokenAsync( "user2", developerClaims); diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseTokenFactoryTest.cs b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseTokenFactoryTest.cs index 9503a925..8d247bbb 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseTokenFactoryTest.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseTokenFactoryTest.cs @@ -56,9 +56,9 @@ public async Task CreateCustomTokenWithClaims() var factory = new FirebaseTokenFactory(new MockSigner(), clock); var developerClaims = new Dictionary() { - {"admin", true}, - {"package", "gold"}, - {"magicNumber", 42L}, + { "admin", true }, + { "package", "gold" }, + { "magicNumber", 42L }, }; var token = await factory.CreateCustomTokenAsync("user2", developerClaims); VerifyCustomToken(token, "user2", developerClaims); @@ -84,7 +84,7 @@ public async Task ReservedClaims() { var developerClaims = new Dictionary() { - {key, "value"}, + { key, "value" }, }; await Assert.ThrowsAsync( async () => await factory.CreateCustomTokenAsync("user", developerClaims)); @@ -142,6 +142,6 @@ public Task SignDataAsync(byte[] data, CancellationToken cancellationTok return Task.FromResult(Encoding.UTF8.GetBytes(Signature)); } - public void Dispose() {} + public void Dispose() { } } } diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseTokenVerifierTest.cs b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseTokenVerifierTest.cs index b1c55f79..310144a6 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseTokenVerifierTest.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseTokenVerifierTest.cs @@ -28,7 +28,7 @@ namespace FirebaseAdmin.Auth.Tests { - public class FirebaseTokenVerifierTest: IDisposable + public class FirebaseTokenVerifierTest : IDisposable { private static readonly IPublicKeySource KeySource = new FileSystemPublicKeySource( "./resources/public_cert.pem"); @@ -57,7 +57,7 @@ public async Task ValidToken() { var payload = new Dictionary() { - {"foo", "bar"}, + { "foo", "bar" }, }; var idToken = await CreateTestTokenAsync(payloadOverrides: payload); var decoded = await TokenVerifier.VerifyTokenAsync(idToken); @@ -95,7 +95,7 @@ public async Task NoKid() { var header = new Dictionary() { - {"kid", string.Empty}, + { "kid", string.Empty }, }; var idToken = await CreateTestTokenAsync(headerOverrides: header); await Assert.ThrowsAsync( @@ -107,7 +107,7 @@ public async Task IncorrectKid() { var header = new Dictionary() { - {"kid", "incorrect-key-id"}, + { "kid", "incorrect-key-id" }, }; var idToken = await CreateTestTokenAsync(headerOverrides: header); await Assert.ThrowsAsync( @@ -119,7 +119,7 @@ public async Task IncorrectAlgorithm() { var header = new Dictionary() { - {"alg", "HS256"}, + { "alg", "HS256" }, }; var idToken = await CreateTestTokenAsync(headerOverrides: header); await Assert.ThrowsAsync( @@ -131,7 +131,7 @@ public async Task Expired() { var payload = new Dictionary() { - {"exp", Clock.UnixTimestamp() - 60}, + { "exp", Clock.UnixTimestamp() - 60 }, }; var idToken = await CreateTestTokenAsync(payloadOverrides: payload); await Assert.ThrowsAsync( @@ -143,7 +143,7 @@ public async Task InvalidIssuedAt() { var payload = new Dictionary() { - {"iat", Clock.UnixTimestamp() + 60}, + { "iat", Clock.UnixTimestamp() + 60 }, }; var idToken = await CreateTestTokenAsync(payloadOverrides: payload); await Assert.ThrowsAsync( @@ -155,7 +155,7 @@ public async Task InvalidIssuer() { var payload = new Dictionary() { - {"iss", "wrong-issuer"}, + { "iss", "wrong-issuer" }, }; var idToken = await CreateTestTokenAsync(payloadOverrides: payload); await Assert.ThrowsAsync( @@ -167,7 +167,7 @@ public async Task InvalidAudience() { var payload = new Dictionary() { - {"aud", "wrong-audience"}, + { "aud", "wrong-audience" }, }; var idToken = await CreateTestTokenAsync(payloadOverrides: payload); await Assert.ThrowsAsync( @@ -179,7 +179,7 @@ public async Task EmptySubject() { var payload = new Dictionary() { - {"sub", string.Empty}, + { "sub", string.Empty }, }; var idToken = await CreateTestTokenAsync(payloadOverrides: payload); await Assert.ThrowsAsync( @@ -256,9 +256,9 @@ internal static async Task CreateTestTokenAsync( { var header = new Dictionary() { - {"alg", "RS256"}, - {"typ", "jwt"}, - {"kid", "test-key-id"}, + { "alg", "RS256" }, + { "typ", "jwt" }, + { "kid", "test-key-id" }, }; if (headerOverrides != null) { diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/FirebaseAdmin.Tests.csproj b/FirebaseAdmin/FirebaseAdmin.Tests/FirebaseAdmin.Tests.csproj index b936e804..903194ec 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/FirebaseAdmin.Tests.csproj +++ b/FirebaseAdmin/FirebaseAdmin.Tests/FirebaseAdmin.Tests.csproj @@ -16,13 +16,13 @@ + + all + - - all - diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/FirebaseAppTest.cs b/FirebaseAdmin/FirebaseAdmin.Tests/FirebaseAppTest.cs index 9268a6ee..65aa0353 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/FirebaseAppTest.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/FirebaseAppTest.cs @@ -20,7 +20,7 @@ namespace FirebaseAdmin.Tests { - public class FirebaseAppTest: IDisposable + public class FirebaseAppTest : IDisposable { private static readonly AppOptions TestOptions = new AppOptions() { @@ -169,7 +169,7 @@ public void GetProjectIdFromServiceAccount() [Fact] public void GetProjectIdFromEnvironment() { - foreach (var name in new string[] {"GOOGLE_CLOUD_PROJECT", "GCLOUD_PROJECT"}) + foreach (var name in new string[] { "GOOGLE_CLOUD_PROJECT", "GCLOUD_PROJECT" }) { Environment.SetEnvironmentVariable(name, "env-project"); try @@ -216,7 +216,7 @@ public void Dispose() } } - internal class MockService: IFirebaseService + internal class MockService : IFirebaseService { public bool Deleted { get; private set; } @@ -226,8 +226,8 @@ public void Delete() } } - internal class OtherMockService: IFirebaseService + internal class OtherMockService : IFirebaseService { - public void Delete() {} + public void Delete() { } } } diff --git a/FirebaseAdmin/FirebaseAdmin/AppOptions.cs b/FirebaseAdmin/FirebaseAdmin/AppOptions.cs index e7a31aaa..1a4bf78f 100644 --- a/FirebaseAdmin/FirebaseAdmin/AppOptions.cs +++ b/FirebaseAdmin/FirebaseAdmin/AppOptions.cs @@ -28,7 +28,7 @@ public sealed class AppOptions /// /// Initializes a new instance of the class. /// - public AppOptions() {} + public AppOptions() { } internal AppOptions(AppOptions options) { diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs index 756fa246..19fe54e0 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs @@ -23,7 +23,7 @@ namespace FirebaseAdmin.Auth /// This is the entry point to all server-side Firebase Authentication operations. You can /// get an instance of this class via FirebaseAuth.DefaultInstance. /// - public sealed class FirebaseAuth: IFirebaseService + public sealed class FirebaseAuth : IFirebaseService { private readonly FirebaseApp _app; private readonly Lazy _tokenFactory; diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenFactory.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenFactory.cs index f6f6b6ac..e4d1a969 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenFactory.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenFactory.cs @@ -24,18 +24,18 @@ using Google.Apis.Auth.OAuth2; using Google.Apis.Util; -[assembly: InternalsVisibleToAttribute("FirebaseAdmin.Tests,PublicKey="+ -"002400000480000094000000060200000024000052534131000400000100010081328559eaab41"+ -"055b84af73469863499d81625dcbba8d8decb298b69e0f783a0958cf471fd4f76327b85a7d4b02"+ -"3003684e85e61cf15f13150008c81f0b75a252673028e530ea95d0c581378da8c6846526ab9597"+ -"4c6d0bc66d2462b51af69968a0e25114bde8811e0d6ee1dc22d4a59eee6a8bba4712cba839652f"+ +[assembly: InternalsVisibleToAttribute("FirebaseAdmin.Tests,PublicKey=" + +"002400000480000094000000060200000024000052534131000400000100010081328559eaab41" + +"055b84af73469863499d81625dcbba8d8decb298b69e0f783a0958cf471fd4f76327b85a7d4b02" + +"3003684e85e61cf15f13150008c81f0b75a252673028e530ea95d0c581378da8c6846526ab9597" + +"4c6d0bc66d2462b51af69968a0e25114bde8811e0d6ee1dc22d4a59eee6a8bba4712cba839652f" + "badddb9c")] namespace FirebaseAdmin.Auth { /// /// A helper class that creates Firebase custom tokens. /// - internal class FirebaseTokenFactory: IDisposable + internal class FirebaseTokenFactory : IDisposable { public const string FirebaseAudience = "https://identitytoolkit.googleapis.com/" + "google.identity.identitytoolkit.v1.IdentityToolkit"; @@ -152,7 +152,7 @@ public void Dispose() } } - internal class CustomTokenPayload: JsonWebToken.Payload + internal class CustomTokenPayload : JsonWebToken.Payload { [Newtonsoft.Json.JsonPropertyAttribute("uid")] public string Uid { get; set; } diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenVerifier.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenVerifier.cs index be1704d8..b1fc8d5d 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenVerifier.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenVerifier.cs @@ -35,7 +35,7 @@ internal sealed class FirebaseTokenVerifier private const string IdTokenCertUrl = "https://www.googleapis.com/robot/v1/metadata/x509/" + "securetoken@system.gserviceaccount.com"; - private const string FirebaseAudience ="https://identitytoolkit.googleapis.com/" + private const string FirebaseAudience = "https://identitytoolkit.googleapis.com/" + "google.identity.identitytoolkit.v1.IdentityToolkit"; // See http://oid-info.com/get/2.16.840.1.101.3.4.2.1 diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/HttpPublicKeySource.cs b/FirebaseAdmin/FirebaseAdmin/Auth/HttpPublicKeySource.cs index ec9269ca..acb29cd8 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/HttpPublicKeySource.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/HttpPublicKeySource.cs @@ -40,7 +40,7 @@ namespace FirebaseAdmin.Auth /// HTTP server. Retrieved keys are cached in memory according to the HTTP cache-control /// directive. /// - internal sealed class HttpPublicKeySource: IPublicKeySource + internal sealed class HttpPublicKeySource : IPublicKeySource { // Default clock skew used by most GCP libraries. This interval is subtracted from the // cache expiry time, before any expiration checks. This helps correct for minor diff --git a/FirebaseAdmin/FirebaseAdmin/FirebaseApp.cs b/FirebaseAdmin/FirebaseAdmin/FirebaseApp.cs index aeafabe3..397ef4c5 100644 --- a/FirebaseAdmin/FirebaseAdmin/FirebaseApp.cs +++ b/FirebaseAdmin/FirebaseAdmin/FirebaseApp.cs @@ -21,11 +21,11 @@ using Google.Apis.Logging; using Google.Apis.Auth.OAuth2; -[assembly: InternalsVisibleToAttribute("FirebaseAdmin.Tests,PublicKey="+ -"002400000480000094000000060200000024000052534131000400000100010081328559eaab41"+ -"055b84af73469863499d81625dcbba8d8decb298b69e0f783a0958cf471fd4f76327b85a7d4b02"+ -"3003684e85e61cf15f13150008c81f0b75a252673028e530ea95d0c581378da8c6846526ab9597"+ -"4c6d0bc66d2462b51af69968a0e25114bde8811e0d6ee1dc22d4a59eee6a8bba4712cba839652f"+ +[assembly: InternalsVisibleToAttribute("FirebaseAdmin.Tests,PublicKey=" + +"002400000480000094000000060200000024000052534131000400000100010081328559eaab41" + +"055b84af73469863499d81625dcbba8d8decb298b69e0f783a0958cf471fd4f76327b85a7d4b02" + +"3003684e85e61cf15f13150008c81f0b75a252673028e530ea95d0c581378da8c6846526ab9597" + +"4c6d0bc66d2462b51af69968a0e25114bde8811e0d6ee1dc22d4a59eee6a8bba4712cba839652f" + "badddb9c")] namespace FirebaseAdmin { diff --git a/stylecop.ruleset b/stylecop.ruleset index b1c65323..5f139441 100644 --- a/stylecop.ruleset +++ b/stylecop.ruleset @@ -4,10 +4,6 @@ - - - - diff --git a/stylecop_test.ruleset b/stylecop_test.ruleset index 6f7fe1ed..e78a40d5 100644 --- a/stylecop_test.ruleset +++ b/stylecop_test.ruleset @@ -4,10 +4,6 @@ - - - - From 03607a5ff51222a12c63fb99bd04d7a5c090dc07 Mon Sep 17 00:00:00 2001 From: hiranya911 Date: Mon, 21 Jan 2019 15:36:15 -0800 Subject: [PATCH 04/13] Fixed more lint errors --- .../FirebaseAuthTest.cs | 13 +- .../IntegrationTestUtils.cs | 15 +- .../Auth/FirebaseAuthTest.cs | 12 +- .../Auth/FirebaseTokenFactoryTest.cs | 4 +- .../Auth/FirebaseTokenVerifierTest.cs | 12 +- .../Auth/HttpPublicKeySourceTest.cs | 4 +- .../FirebaseAdmin.Tests/Auth/IAMSignerTest.cs | 2 +- .../Auth/ServiceAccountSignerTest.cs | 6 +- .../FirebaseAdmin.Tests/FirebaseAppTest.cs | 2 +- .../FirebaseAdmin.Tests/MockClock.cs | 12 +- .../FirebaseAdmin.Tests/MockMessageHandler.cs | 6 +- .../FirebaseAdmin/Auth/FirebaseAuth.cs | 40 ++-- .../Auth/FirebaseTokenFactory.cs | 20 +- .../Auth/FirebaseTokenVerifier.cs | 127 +++++------ .../FirebaseAdmin/Auth/HttpPublicKeySource.cs | 42 ++-- FirebaseAdmin/FirebaseAdmin/Auth/IAMSigner.cs | 72 +++---- FirebaseAdmin/FirebaseAdmin/Auth/JwtUtils.cs | 24 +-- .../Auth/ServiceAccountSigner.cs | 8 +- FirebaseAdmin/FirebaseAdmin/FirebaseApp.cs | 202 +++++++++--------- stylecop.ruleset | 11 +- stylecop_test.ruleset | 7 +- 21 files changed, 320 insertions(+), 321 deletions(-) diff --git a/FirebaseAdmin/FirebaseAdmin.IntegrationTests/FirebaseAuthTest.cs b/FirebaseAdmin/FirebaseAdmin.IntegrationTests/FirebaseAuthTest.cs index bf8a467e..d572b5f8 100644 --- a/FirebaseAdmin/FirebaseAdmin.IntegrationTests/FirebaseAuthTest.cs +++ b/FirebaseAdmin/FirebaseAdmin.IntegrationTests/FirebaseAuthTest.cs @@ -17,11 +17,11 @@ using System.Net.Http; using System.Text; using System.Threading.Tasks; -using Xunit; using FirebaseAdmin; using FirebaseAdmin.Auth; using Google.Apis.Auth.OAuth2; using Google.Apis.Util; +using Xunit; namespace FirebaseAdmin.IntegrationTests { @@ -74,11 +74,12 @@ public async Task CreateCustomTokenWithoutServiceAccount() var googleCred = FirebaseApp.DefaultInstance.Options.Credential; var serviceAcct = (ServiceAccountCredential)googleCred.UnderlyingCredential; var token = await ((ITokenAccess)googleCred).GetAccessTokenForRequestAsync(); - var app = FirebaseApp.Create(new AppOptions() - { - Credential = GoogleCredential.FromAccessToken(token), - ServiceAccountId = serviceAcct.Id, - }, "IAMSignApp"); + var app = FirebaseApp.Create( + new AppOptions() + { + Credential = GoogleCredential.FromAccessToken(token), + ServiceAccountId = serviceAcct.Id, + }, "IAMSignApp"); try { var customToken = await FirebaseAuth.GetAuth(app).CreateCustomTokenAsync( diff --git a/FirebaseAdmin/FirebaseAdmin.IntegrationTests/IntegrationTestUtils.cs b/FirebaseAdmin/FirebaseAdmin.IntegrationTests/IntegrationTestUtils.cs index b2be8bff..bee0adc0 100644 --- a/FirebaseAdmin/FirebaseAdmin.IntegrationTests/IntegrationTestUtils.cs +++ b/FirebaseAdmin/FirebaseAdmin.IntegrationTests/IntegrationTestUtils.cs @@ -26,14 +26,15 @@ internal static class IntegrationTestUtils private const string ServiceAccountFile = "./resources/integration_cert.json"; private const string ApiKeyFile = "./resources/integration_apikey.txt"; - private static readonly Lazy DefaultFirebaseApp = new Lazy(() => - { - var options = new AppOptions() + private static readonly Lazy DefaultFirebaseApp = new Lazy( + () => { - Credential = GoogleCredential.FromFile(ServiceAccountFile), - }; - return FirebaseApp.Create(options); - }, true); + var options = new AppOptions() + { + Credential = GoogleCredential.FromFile(ServiceAccountFile), + }; + return FirebaseApp.Create(options); + }, true); public static FirebaseApp EnsureDefaultApp() { diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseAuthTest.cs b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseAuthTest.cs index 4df8974e..2740a250 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseAuthTest.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseAuthTest.cs @@ -20,10 +20,10 @@ using System.Text; using System.Threading; using System.Threading.Tasks; -using Xunit; using FirebaseAdmin.Auth; using Google.Apis.Auth; using Google.Apis.Auth.OAuth2; +using Xunit; [assembly: CollectionBehavior(DisableTestParallelization = true)] namespace FirebaseAdmin.Auth.Tests @@ -141,6 +141,11 @@ await Assert.ThrowsAnyAsync( idToken, canceller.Token)); } + public void Dispose() + { + FirebaseApp.DeleteAll(); + } + private static void VerifyCustomToken(string token, string uid, Dictionary claims) { string[] segments = token.Split("."); @@ -172,10 +177,5 @@ private static void VerifyCustomToken(string token, string uid, Dictionary _rsa; + private IReadOnlyList rsa; public FileSystemPublicKeySource(string file) { var x509cert = new X509Certificate2(File.ReadAllBytes(file)); var rsa = (RSA)x509cert.PublicKey.Key; - _rsa = ImmutableList.Create(new PublicKey("test-key-id", rsa)); + this.rsa = ImmutableList.Create(new PublicKey("test-key-id", rsa)); } public Task> GetPublicKeysAsync( CancellationToken cancellationToken) { - return Task.FromResult(_rsa); + return Task.FromResult(this.rsa); } } } diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/HttpPublicKeySourceTest.cs b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/HttpPublicKeySourceTest.cs index 1a53a4a0..cf4406b4 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/HttpPublicKeySourceTest.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/HttpPublicKeySourceTest.cs @@ -18,9 +18,9 @@ using System.Net.Http; using System.Net.Http.Headers; using System.Threading.Tasks; -using Xunit; -using FirebaseAdmin.Tests; using FirebaseAdmin.Auth; +using FirebaseAdmin.Tests; +using Xunit; namespace FirebaseAdmin.Auth.Tests { diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/IAMSignerTest.cs b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/IAMSignerTest.cs index f454953b..ea72c041 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/IAMSignerTest.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/IAMSignerTest.cs @@ -19,11 +19,11 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using FirebaseAdmin.Tests; using Google.Apis.Auth.OAuth2; using Google.Apis.Http; using Google.Apis.Json; using Xunit; -using FirebaseAdmin.Tests; namespace FirebaseAdmin.Auth.Tests { diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/ServiceAccountSignerTest.cs b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/ServiceAccountSignerTest.cs index 8b0811b8..ab51c2a1 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/ServiceAccountSignerTest.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/ServiceAccountSignerTest.cs @@ -18,9 +18,9 @@ using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading.Tasks; -using Xunit; using FirebaseAdmin.Auth; using Google.Apis.Auth.OAuth2; +using Xunit; namespace FirebaseAdmin.Auth.Tests { @@ -32,8 +32,8 @@ public async Task Signer() var credential = GoogleCredential.FromFile("./resources/service_account.json"); var serviceAccount = (ServiceAccountCredential)credential.UnderlyingCredential; var signer = new ServiceAccountSigner(serviceAccount); - Assert.Equal("client@test-project.iam.gserviceaccount.com", - await signer.GetKeyIdAsync()); + Assert.Equal( + "client@test-project.iam.gserviceaccount.com", await signer.GetKeyIdAsync()); byte[] data = Encoding.UTF8.GetBytes("Hello world"); byte[] signature = signer.SignDataAsync(data).Result; Assert.True(Verify(data, signature)); diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/FirebaseAppTest.cs b/FirebaseAdmin/FirebaseAdmin.Tests/FirebaseAppTest.cs index 65aa0353..1b7307a9 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/FirebaseAppTest.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/FirebaseAppTest.cs @@ -14,9 +14,9 @@ using System; using System.Threading.Tasks; -using Xunit; using FirebaseAdmin; using Google.Apis.Auth.OAuth2; +using Xunit; namespace FirebaseAdmin.Tests { diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/MockClock.cs b/FirebaseAdmin/FirebaseAdmin.Tests/MockClock.cs index c68cf24e..3d26ca34 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/MockClock.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/MockClock.cs @@ -19,8 +19,8 @@ namespace FirebaseAdmin.Tests { public class MockClock : IClock { - private object _lock = new object(); - private DateTime _utcNow; + private object mutex = new object(); + private DateTime utcNow; public MockClock() { @@ -37,17 +37,17 @@ public DateTime UtcNow { get { - lock (_lock) + lock (this.mutex) { - return _utcNow; + return this.utcNow; } } set { - lock (_lock) + lock (this.mutex) { - _utcNow = value; + this.utcNow = value; } } } diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/MockMessageHandler.cs b/FirebaseAdmin/FirebaseAdmin.Tests/MockMessageHandler.cs index 1feff6f7..ebd34534 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/MockMessageHandler.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/MockMessageHandler.cs @@ -90,17 +90,17 @@ protected override async Task SendAsyncCore( /// internal abstract class CountableMessageHandler : HttpMessageHandler { - private int _calls; + private int calls; public int Calls { - get { return _calls; } + get { return this.calls; } } protected sealed override Task SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) { - Interlocked.Increment(ref _calls); + Interlocked.Increment(ref this.calls); return SendAsyncCore(request, cancellationToken); } diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs index 19fe54e0..275aae3f 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs @@ -25,19 +25,19 @@ namespace FirebaseAdmin.Auth /// public sealed class FirebaseAuth : IFirebaseService { - private readonly FirebaseApp _app; - private readonly Lazy _tokenFactory; - private readonly Lazy _idTokenVerifier; - private readonly object _lock = new object(); - private bool _deleted; + private readonly FirebaseApp app; + private readonly Lazy tokenFactory; + private readonly Lazy idTokenVerifier; + private readonly object authLock = new object(); + private bool deleted; private FirebaseAuth(FirebaseApp app) { - _app = app; - _tokenFactory = new Lazy(() => - FirebaseTokenFactory.Create(_app), true); - _idTokenVerifier = new Lazy(() => - FirebaseTokenVerifier.CreateIDTokenVerifier(_app), true); + this.app = app; + this.tokenFactory = new Lazy( + () => FirebaseTokenFactory.Create(this.app), true); + this.idTokenVerifier = new Lazy( + () => FirebaseTokenVerifier.CreateIDTokenVerifier(this.app), true); } /// @@ -207,13 +207,13 @@ public async Task CreateCustomTokenAsync( CancellationToken cancellationToken) { FirebaseTokenFactory tokenFactory; - lock (_lock) + lock (this.authLock) { - if (_deleted) + if (this.deleted) { throw new InvalidOperationException("Cannot invoke after deleting the app."); } - tokenFactory = _tokenFactory.Value; + tokenFactory = this.tokenFactory.Value; } return await tokenFactory.CreateCustomTokenAsync( uid, developerClaims, cancellationToken).ConfigureAwait(false); @@ -261,25 +261,25 @@ public async Task VerifyIdTokenAsync(string idToken) public async Task VerifyIdTokenAsync( string idToken, CancellationToken cancellationToken) { - lock (_lock) + lock (this.authLock) { - if (_deleted) + if (this.deleted) { throw new InvalidOperationException("Cannot invoke after deleting the app."); } } - return await _idTokenVerifier.Value.VerifyTokenAsync(idToken, cancellationToken) + return await this.idTokenVerifier.Value.VerifyTokenAsync(idToken, cancellationToken) .ConfigureAwait(false); } void IFirebaseService.Delete() { - lock (_lock) + lock (this.authLock) { - _deleted = true; - if (_tokenFactory.IsValueCreated) + this.deleted = true; + if (this.tokenFactory.IsValueCreated) { - _tokenFactory.Value.Dispose(); + this.tokenFactory.Value.Dispose(); } } } diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenFactory.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenFactory.cs index e4d1a969..4c0c1e43 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenFactory.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenFactory.cs @@ -15,13 +15,13 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Runtime.CompilerServices; using System.Text; using System.Threading; using System.Threading.Tasks; -using System.Runtime.CompilerServices; using Google.Apis.Auth; -using Google.Apis.Http; using Google.Apis.Auth.OAuth2; +using Google.Apis.Http; using Google.Apis.Util; [assembly: InternalsVisibleToAttribute("FirebaseAdmin.Tests,PublicKey=" + @@ -62,13 +62,13 @@ internal class FirebaseTokenFactory : IDisposable "nonce", "sub"); - private readonly ISigner _signer; - private readonly IClock _clock; + private readonly ISigner signer; + private readonly IClock clock; public FirebaseTokenFactory(ISigner signer, IClock clock) { - _signer = signer.ThrowIfNull(nameof(signer)); - _clock = clock.ThrowIfNull(nameof(clock)); + this.signer = signer.ThrowIfNull(nameof(signer)); + this.clock = clock.ThrowIfNull(nameof(clock)); } public static FirebaseTokenFactory Create(FirebaseApp app) @@ -127,8 +127,8 @@ public async Task CreateCustomTokenAsync( Type = "JWT", }; - var issued = (int)(_clock.UtcNow - UnixEpoch).TotalSeconds; - var keyId = await _signer.GetKeyIdAsync(cancellationToken).ConfigureAwait(false); + var issued = (int)(this.clock.UtcNow - UnixEpoch).TotalSeconds; + var keyId = await this.signer.GetKeyIdAsync(cancellationToken).ConfigureAwait(false); var payload = new CustomTokenPayload() { Uid = uid, @@ -143,12 +143,12 @@ public async Task CreateCustomTokenAsync( payload.Claims = developerClaims; } return await JwtUtils.CreateSignedJwtAsync( - header, payload, _signer, cancellationToken).ConfigureAwait(false); + header, payload, this.signer, cancellationToken).ConfigureAwait(false); } public void Dispose() { - _signer.Dispose(); + signer.Dispose(); } } diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenVerifier.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenVerifier.cs index b1fc8d5d..4bf18cf1 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenVerifier.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenVerifier.cs @@ -44,103 +44,126 @@ internal sealed class FirebaseTokenVerifier private static readonly IReadOnlyList StandardClaims = ImmutableList.Create("iss", "aud", "exp", "iat", "sub", "uid"); - private readonly string _shortName; - private readonly string _articledShortName; - private readonly string _operation; - private readonly string _url; - private readonly string _issuer; - private readonly IClock _clock; - private readonly IPublicKeySource _keySource; + private readonly string shortName; + private readonly string articledShortName; + private readonly string operation; + private readonly string url; + private readonly string issuer; + private readonly IClock clock; + private readonly IPublicKeySource keySource; internal FirebaseTokenVerifier(FirebaseTokenVerifierArgs args) { ProjectId = args.ProjectId.ThrowIfNullOrEmpty(nameof(args.ProjectId)); - _shortName = args.ShortName.ThrowIfNullOrEmpty(nameof(args.ShortName)); - _operation = args.Operation.ThrowIfNullOrEmpty(nameof(args.Operation)); - _url = args.Url.ThrowIfNullOrEmpty(nameof(args.Url)); - _issuer = args.Issuer.ThrowIfNullOrEmpty(nameof(args.Issuer)); - _clock = args.Clock.ThrowIfNull(nameof(args.Clock)); - _keySource = args.PublicKeySource.ThrowIfNull(nameof(args.PublicKeySource)); - if ("aeiou".Contains(_shortName.ToLower().Substring(0, 1))) + this.shortName = args.ShortName.ThrowIfNullOrEmpty(nameof(args.ShortName)); + this.operation = args.Operation.ThrowIfNullOrEmpty(nameof(args.Operation)); + this.url = args.Url.ThrowIfNullOrEmpty(nameof(args.Url)); + this.issuer = args.Issuer.ThrowIfNullOrEmpty(nameof(args.Issuer)); + this.clock = args.Clock.ThrowIfNull(nameof(args.Clock)); + this.keySource = args.PublicKeySource.ThrowIfNull(nameof(args.PublicKeySource)); + if ("aeiou".Contains(this.shortName.ToLower().Substring(0, 1))) { - _articledShortName = $"an {_shortName}"; + this.articledShortName = $"an {this.shortName}"; } else { - _articledShortName = $"a {_shortName}"; + this.articledShortName = $"a {this.shortName}"; } } public string ProjectId { get; } + internal static FirebaseTokenVerifier CreateIDTokenVerifier(FirebaseApp app) + { + var projectId = app.GetProjectId(); + if (string.IsNullOrEmpty(projectId)) + { + throw new ArgumentException( + "Must initialize FirebaseApp with a project ID to verify ID tokens."); + } + var keySource = new HttpPublicKeySource( + IdTokenCertUrl, SystemClock.Default, new HttpClientFactory()); + var args = new FirebaseTokenVerifierArgs() + { + ProjectId = projectId, + ShortName = "ID token", + Operation = "VerifyIdTokenAsync()", + Url = "https://firebase.google.com/docs/auth/admin/verify-id-tokens", + Issuer = "https://securetoken.google.com/", + Clock = SystemClock.Default, + PublicKeySource = keySource, + }; + return new FirebaseTokenVerifier(args); + } + internal async Task VerifyTokenAsync( string token, CancellationToken cancellationToken = default(CancellationToken)) { if (string.IsNullOrEmpty(token)) { - throw new ArgumentException($"{_shortName} must not be null or empty."); + throw new ArgumentException($"{this.shortName} must not be null or empty."); } string[] segments = token.Split('.'); if (segments.Length != 3) { - throw new FirebaseException($"Incorrect number of segments in ${_shortName}."); + throw new FirebaseException($"Incorrect number of segments in ${this.shortName}."); } var header = JwtUtils.Decode(segments[0]); var payload = JwtUtils.Decode(segments[1]); - var projectIdMessage = $"Make sure the {_shortName} comes from the same Firebase " + var projectIdMessage = $"Make sure the {this.shortName} comes from the same Firebase " + "project as the credential used to initialize this SDK."; - var verifyTokenMessage = $"See {_url} for details on how to retrieve a value " - + $"{_shortName}."; - var issuer = _issuer + ProjectId; + var verifyTokenMessage = $"See {this.url} for details on how to retrieve a value " + + $"{this.shortName}."; + var issuer = this.issuer + ProjectId; string error = null; if (string.IsNullOrEmpty(header.KeyId)) { if (payload.Audience == FirebaseAudience) { - error = $"{_operation} expects {_articledShortName}, but was given a custom " + error = $"{this.operation} expects {this.articledShortName}, but was given a custom " + "token."; } else if (header.Algorithm == "HS256") { - error = $"{_operation} expects {_articledShortName}, but was given a legacy " + error = $"{this.operation} expects {this.articledShortName}, but was given a legacy " + "custom token."; } else { - error = $"Firebase {_shortName} has no 'kid' claim."; + error = $"Firebase {this.shortName} has no 'kid' claim."; } } else if (header.Algorithm != "RS256") { - error = $"Firebase {_shortName} has incorrect algorithm. Expected RS256 but got " + error = $"Firebase {this.shortName} has incorrect algorithm. Expected RS256 but got " + $"{header.Algorithm}. {verifyTokenMessage}"; } else if (ProjectId != payload.Audience) { - error = $"{_shortName} has incorrect audience (aud) claim. Expected {ProjectId} " + error = $"{this.shortName} has incorrect audience (aud) claim. Expected {ProjectId} " + $"but got {payload.Audience}. {projectIdMessage} {verifyTokenMessage}"; } else if (payload.Issuer != issuer) { - error = $"{_shortName} has incorrect issuer (iss) claim. Expected {issuer} but " + error = $"{this.shortName} has incorrect issuer (iss) claim. Expected {issuer} but " + $"got {payload.Issuer}. {projectIdMessage} {verifyTokenMessage}"; } - else if (payload.IssuedAtTimeSeconds > _clock.UnixTimestamp()) + else if (payload.IssuedAtTimeSeconds > this.clock.UnixTimestamp()) { - error = $"Firebase {_shortName} issued at future timestamp"; + error = $"Firebase {this.shortName} issued at future timestamp"; } - else if (payload.ExpirationTimeSeconds < _clock.UnixTimestamp()) + else if (payload.ExpirationTimeSeconds < this.clock.UnixTimestamp()) { - error = $"Firebase {_shortName} expired at {payload.ExpirationTimeSeconds}"; + error = $"Firebase {this.shortName} expired at {payload.ExpirationTimeSeconds}"; } else if (string.IsNullOrEmpty(payload.Subject)) { - error = $"Firebase {_shortName} has no or empty subject (sub) claim."; + error = $"Firebase {this.shortName} has no or empty subject (sub) claim."; } else if (payload.Subject.Length > 128) { - error = $"Firebase {_shortName} has a subject claim longer than 128 characters."; + error = $"Firebase {this.shortName} has a subject claim longer than 128 characters."; } if (error != null) @@ -164,7 +187,14 @@ await VerifySignatureAsync(segments, header.KeyId, cancellationToken) /// Verifies the integrity of a JWT by validating its signature. The JWT must be specified /// as an array of three segments (header, body and signature). /// - [SuppressMessage("StyleCop.Analyzers", "SA1009:ClosingParenthesisMustBeSpacedCorrectly", Justification = "Use of directives.")] + [SuppressMessage( + "StyleCop.Analyzers", + "SA1009:ClosingParenthesisMustBeSpacedCorrectly", + Justification = "Use of directives.")] + [SuppressMessage( + "StyleCop.Analyzers", + "SA1111:ClosingParenthesisMustBeOnLineOfLastParameter", + Justification = "Use of directives.")] private async Task VerifySignatureAsync( string[] segments, string keyId, CancellationToken cancellationToken) { @@ -175,7 +205,7 @@ private async Task VerifySignatureAsync( Encoding.ASCII.GetBytes($"{segments[0]}.{segments[1]}")); } var signature = JwtUtils.Base64DecodeToBytes(segments[2]); - var keys = await _keySource.GetPublicKeysAsync(cancellationToken) + var keys = await this.keySource.GetPublicKeysAsync(cancellationToken) .ConfigureAwait(false); var verified = keys.Any(key => #if NETSTANDARD1_5 || NETSTANDARD2_0 @@ -190,32 +220,9 @@ private async Task VerifySignatureAsync( ); if (!verified) { - throw new FirebaseException($"Failed to verify {_shortName} signature."); + throw new FirebaseException($"Failed to verify {this.shortName} signature."); } } - - internal static FirebaseTokenVerifier CreateIDTokenVerifier(FirebaseApp app) - { - var projectId = app.GetProjectId(); - if (string.IsNullOrEmpty(projectId)) - { - throw new ArgumentException( - "Must initialize FirebaseApp with a project ID to verify ID tokens."); - } - var keySource = new HttpPublicKeySource( - IdTokenCertUrl, SystemClock.Default, new HttpClientFactory()); - var args = new FirebaseTokenVerifierArgs() - { - ProjectId = projectId, - ShortName = "ID token", - Operation = "VerifyIdTokenAsync()", - Url = "https://firebase.google.com/docs/auth/admin/verify-id-tokens", - Issuer = "https://securetoken.google.com/", - Clock = SystemClock.Default, - PublicKeySource = keySource, - }; - return new FirebaseTokenVerifier(args); - } } internal sealed class FirebaseTokenVerifierArgs diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/HttpPublicKeySource.cs b/FirebaseAdmin/FirebaseAdmin/Auth/HttpPublicKeySource.cs index acb29cd8..1efeb1c7 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/HttpPublicKeySource.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/HttpPublicKeySource.cs @@ -21,8 +21,8 @@ using System.Text; using System.Threading; using System.Threading.Tasks; -using Google.Apis.Json; using Google.Apis.Http; +using Google.Apis.Json; using Google.Apis.Util; #if NETSTANDARD1_5 || NETSTANDARD2_0 @@ -48,44 +48,44 @@ internal sealed class HttpPublicKeySource : IPublicKeySource // pre-emptively refreshed instead of waiting until the last second. private static readonly TimeSpan ClockSkew = new TimeSpan(hours: 0, minutes: 5, seconds: 0); - private readonly SemaphoreSlim _lock = new SemaphoreSlim(1, 1); - private readonly string _certUrl; - private readonly IClock _clock; - private readonly HttpClientFactory _clientFactory; - private DateTime _expirationTime; - private IReadOnlyList _cachedKeys; + private readonly SemaphoreSlim cacheLock = new SemaphoreSlim(1, 1); + private readonly string certUrl; + private readonly IClock clock; + private readonly HttpClientFactory clientFactory; + private DateTime expirationTime; + private IReadOnlyList cachedKeys; public HttpPublicKeySource(string certUrl, IClock clock, HttpClientFactory clientFactory) { - _certUrl = certUrl.ThrowIfNullOrEmpty(nameof(certUrl)); - _clock = clock.ThrowIfNull(nameof(clock)); - _clientFactory = clientFactory.ThrowIfNull(nameof(clientFactory)); - _expirationTime = clock.UtcNow; + this.certUrl = certUrl.ThrowIfNullOrEmpty(nameof(certUrl)); + this.clock = clock.ThrowIfNull(nameof(clock)); + this.clientFactory = clientFactory.ThrowIfNull(nameof(clientFactory)); + this.expirationTime = clock.UtcNow; } public async Task> GetPublicKeysAsync( CancellationToken cancellationToken = default(CancellationToken)) { - if (_cachedKeys == null || _clock.UtcNow >= _expirationTime) + if (cachedKeys == null || clock.UtcNow >= expirationTime) { - await _lock.WaitAsync(cancellationToken).ConfigureAwait(false); + await cacheLock.WaitAsync(cancellationToken).ConfigureAwait(false); try { - var now = _clock.UtcNow; - if (_cachedKeys == null || now >= _expirationTime) + var now = clock.UtcNow; + if (cachedKeys == null || now >= expirationTime) { - using (var httpClient = _clientFactory.CreateDefaultHttpClient()) + using (var httpClient = clientFactory.CreateDefaultHttpClient()) { - var response = await httpClient.GetAsync(_certUrl, cancellationToken) + var response = await httpClient.GetAsync(certUrl, cancellationToken) .ConfigureAwait(false); response.EnsureSuccessStatusCode(); - _cachedKeys = ParseKeys(await response.Content.ReadAsStringAsync() + cachedKeys = ParseKeys(await response.Content.ReadAsStringAsync() .ConfigureAwait(false)); var cacheControl = response.Headers.CacheControl; if (cacheControl?.MaxAge != null) { - _expirationTime = now.Add(cacheControl.MaxAge.Value) + expirationTime = now.Add(cacheControl.MaxAge.Value) .Subtract(ClockSkew); } } @@ -97,11 +97,11 @@ public async Task> GetPublicKeysAsync( } finally { - _lock.Release(); + cacheLock.Release(); } } - return _cachedKeys; + return cachedKeys; } private IReadOnlyList ParseKeys(string json) diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/IAMSigner.cs b/FirebaseAdmin/FirebaseAdmin/Auth/IAMSigner.cs index 6bc627b1..2d8b283c 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/IAMSigner.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/IAMSigner.cs @@ -40,13 +40,13 @@ internal class IAMSigner : ISigner private const string MetadataServerUrl = "http://metadata/computeMetadata/v1/instance/service-accounts/default/email"; - private readonly ConfigurableHttpClient _httpClient; - private readonly Lazy> _keyId; + private readonly ConfigurableHttpClient httpClient; + private readonly Lazy> keyId; public IAMSigner(HttpClientFactory clientFactory, GoogleCredential credential) { - _httpClient = clientFactory.CreateAuthorizedHttpClient(credential); - _keyId = new Lazy>( + this.httpClient = clientFactory.CreateAuthorizedHttpClient(credential); + this.keyId = new Lazy>( async () => await DiscoverServiceAccountIdAsync(clientFactory) .ConfigureAwait(false), true); } @@ -62,7 +62,7 @@ public async Task SignDataAsync( }; try { - var response = await _httpClient.PostJsonAsync(url, request, cancellationToken) + var response = await httpClient.PostJsonAsync(url, request, cancellationToken) .ConfigureAwait(false); var json = await response.Content.ReadAsStringAsync().ConfigureAwait(false); ThrowIfError(response, json); @@ -75,37 +75,12 @@ public async Task SignDataAsync( } } - private void ThrowIfError(HttpResponseMessage response, string content) - { - if (response.IsSuccessStatusCode) - { - return; - } - string error = null; - try - { - var result = NewtonsoftJsonSerializer.Instance.Deserialize(content); - error = result?.Error.Message; - } - catch (Exception) - { - // Ignore any errors encountered while parsing the originl error. - } - if (string.IsNullOrEmpty(error)) - { - error = "Response status code does not indicate success: " - + $"{(int)response.StatusCode} ({response.StatusCode})" - + $"{Environment.NewLine}{content}"; - } - throw new FirebaseException(error); - } - public virtual async Task GetKeyIdAsync( CancellationToken cancellationToken = default(CancellationToken)) { try { - return await _keyId.Value.ConfigureAwait(false); + return await keyId.Value.ConfigureAwait(false); } catch (Exception e) { @@ -118,6 +93,11 @@ public virtual async Task GetKeyIdAsync( } } + public void Dispose() + { + httpClient.Dispose(); + } + private static async Task DiscoverServiceAccountIdAsync( HttpClientFactory clientFactory) { @@ -128,9 +108,29 @@ private static async Task DiscoverServiceAccountIdAsync( } } - public void Dispose() + private void ThrowIfError(HttpResponseMessage response, string content) { - _httpClient.Dispose(); + if (response.IsSuccessStatusCode) + { + return; + } + string error = null; + try + { + var result = NewtonsoftJsonSerializer.Instance.Deserialize(content); + error = result?.Error.Message; + } + catch (Exception) + { + // Ignore any errors encountered while parsing the originl error. + } + if (string.IsNullOrEmpty(error)) + { + error = "Response status code does not indicate success: " + + $"{(int)response.StatusCode} ({response.StatusCode})" + + $"{Environment.NewLine}{content}"; + } + throw new FirebaseException(error); } } @@ -177,19 +177,19 @@ internal class SignBlobErrorDetail /// internal sealed class FixedAccountIAMSigner : IAMSigner { - private readonly string _keyId; + private readonly string keyId; public FixedAccountIAMSigner( HttpClientFactory clientFactory, GoogleCredential credential, string keyId) : base(clientFactory, credential) { - _keyId = keyId.ThrowIfNullOrEmpty(nameof(keyId)); + this.keyId = keyId.ThrowIfNullOrEmpty(nameof(keyId)); } public override Task GetKeyIdAsync( CancellationToken cancellationToken = default(CancellationToken)) { - return Task.FromResult(_keyId); + return Task.FromResult(this.keyId); } } } \ No newline at end of file diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/JwtUtils.cs b/FirebaseAdmin/FirebaseAdmin/Auth/JwtUtils.cs index 8fc8f9ec..aabd62b0 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/JwtUtils.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/JwtUtils.cs @@ -25,12 +25,6 @@ namespace FirebaseAdmin.Auth /// internal static class JwtUtils { - private static string Encode(object obj) - { - var json = NewtonsoftJsonSerializer.Instance.Serialize(obj); - return UrlSafeBase64Encode(Encoding.UTF8.GetBytes(json)); - } - /// /// Decodes a single JWT segment, and deserializes it into a value of type /// . @@ -44,12 +38,6 @@ public static T Decode(string value) return NewtonsoftJsonSerializer.Instance.Deserialize(json); } - private static string UrlSafeBase64Encode(byte[] bytes) - { - var base64Value = Convert.ToBase64String(bytes); - return base64Value.TrimEnd('=').Replace('+', '-').Replace('/', '_'); - } - internal static string Base64Decode(string input) { var raw = Base64DecodeToBytes(input); @@ -87,5 +75,17 @@ internal static async Task CreateSignedJwtAsync( assertion.Append('.').Append(UrlSafeBase64Encode(signature)); return assertion.ToString(); } + + private static string Encode(object obj) + { + var json = NewtonsoftJsonSerializer.Instance.Serialize(obj); + return UrlSafeBase64Encode(Encoding.UTF8.GetBytes(json)); + } + + private static string UrlSafeBase64Encode(byte[] bytes) + { + var base64Value = Convert.ToBase64String(bytes); + return base64Value.TrimEnd('=').Replace('+', '-').Replace('/', '_'); + } } } diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/ServiceAccountSigner.cs b/FirebaseAdmin/FirebaseAdmin/Auth/ServiceAccountSigner.cs index ddd2614b..f47dc0ac 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/ServiceAccountSigner.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/ServiceAccountSigner.cs @@ -25,7 +25,7 @@ namespace FirebaseAdmin.Auth /// internal sealed class ServiceAccountSigner : ISigner { - private readonly ServiceAccountCredential _credential; + private readonly ServiceAccountCredential credential; public ServiceAccountSigner(ServiceAccountCredential credential) { @@ -33,18 +33,18 @@ public ServiceAccountSigner(ServiceAccountCredential credential) { throw new ArgumentNullException("Credential must not be null."); } - _credential = credential; + this.credential = credential; } public Task GetKeyIdAsync(CancellationToken cancellationToken = default(CancellationToken)) { - return Task.FromResult(_credential.Id); + return Task.FromResult(credential.Id); } public Task SignDataAsync(byte[] data, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); - var signature = _credential.CreateSignature(data); + var signature = credential.CreateSignature(data); return Task.FromResult(Convert.FromBase64String(signature)); } diff --git a/FirebaseAdmin/FirebaseAdmin/FirebaseApp.cs b/FirebaseAdmin/FirebaseAdmin/FirebaseApp.cs index 397ef4c5..cee07c13 100644 --- a/FirebaseAdmin/FirebaseAdmin/FirebaseApp.cs +++ b/FirebaseAdmin/FirebaseAdmin/FirebaseApp.cs @@ -18,8 +18,8 @@ using System.Runtime.CompilerServices; using System.Threading.Tasks; using Google; -using Google.Apis.Logging; using Google.Apis.Auth.OAuth2; +using Google.Apis.Logging; [assembly: InternalsVisibleToAttribute("FirebaseAdmin.Tests,PublicKey=" + "002400000480000094000000060200000024000052534131000400000100010081328559eaab41" + @@ -41,8 +41,6 @@ internal delegate TResult ServiceFactory() /// public sealed class FirebaseApp { - private const string DefaultAppName = "[DEFAULT]"; - internal static readonly IReadOnlyList DefaultScopes = ImmutableList.Create( "https://www.googleapis.com/auth/firebase", // RTDB. "https://www.googleapis.com/auth/userinfo.email", // RTDB @@ -51,30 +49,32 @@ public sealed class FirebaseApp "https://www.googleapis.com/auth/cloud-platform", // Cloud Firestore "https://www.googleapis.com/auth/datastore"); + private const string DefaultAppName = "[DEFAULT]"; + private static readonly Dictionary Apps = new Dictionary(); private static readonly ILogger Logger = ApplicationContext.Logger.ForType(); // Guards the mutable state local to an app instance. - private readonly object _lock = new object(); - private readonly AppOptions _options; + private readonly object appLock = new object(); + private readonly AppOptions options; // A collection of stateful services initialized using this app instance (e.g. // FirebaseAuth). Services are tracked here so they can be cleaned up when the app is // deleted. - private readonly Dictionary _services = new Dictionary(); - private bool _deleted = false; + private readonly Dictionary services = new Dictionary(); + private bool deleted = false; private FirebaseApp(AppOptions options, string name) { - _options = new AppOptions(options); - if (_options.Credential == null) + this.options = new AppOptions(options); + if (options.Credential == null) { throw new ArgumentNullException("Credential must be set"); } - if (_options.Credential.IsCreateScopedRequired) + if (options.Credential.IsCreateScopedRequired) { - _options.Credential = _options.Credential.CreateScoped(DefaultScopes); + options.Credential = options.Credential.CreateScoped(DefaultScopes); } Name = name; } @@ -98,7 +98,7 @@ public AppOptions Options { get { - return new AppOptions(_options); + return new AppOptions(this.options); } } @@ -108,80 +108,24 @@ public AppOptions Options public string Name { get; } /// - /// Deletes this app instance and cleans up any state associated with it. Once an app has - /// been deleted, accessing any services related to it will result in an exception. - /// If the app is already deleted, this method is a no-op. + /// Returns the app instance identified by the given name. /// - public void Delete() + /// The instance with the specified name or null if it + /// doesn't exist. + /// If the name argument is null or empty. + /// Name of the app to retrieve. + public static FirebaseApp GetInstance(string name) { - // Clean up local state - lock (_lock) + if (string.IsNullOrEmpty(name)) { - _deleted = true; - foreach (var entry in _services) - { - try - { - entry.Value.Delete(); - } - catch (Exception e) - { - Logger.Error(e, "Error while cleaning up service {0}", entry.Key); - } - } - _services.Clear(); + throw new ArgumentException("App name to lookup must not be null or empty"); } - // Clean up global state lock (Apps) { - Apps.Remove(Name); - } - } - - internal T GetOrInit(string id, ServiceFactory initializer) - where T : class, IFirebaseService - { - lock (_lock) - { - if (_deleted) - { - throw new InvalidOperationException("Cannot use an app after it has been deleted"); - } - IFirebaseService service; - if (!_services.TryGetValue(id, out service)) - { - service = initializer(); - _services.Add(id, service); - } - return (T)service; - } - } - - /// - /// Returns the Google Cloud Platform project ID associated with this Firebase app. If a - /// project ID is specified in , that value is returned. If not - /// attempts to determine a project ID from the used to - /// initialize the app. Looks up the GOOGLE_CLOUD_PROJECT environment variable when all - /// else fails. - /// - /// A project ID string or null. - internal string GetProjectId() - { - if (!string.IsNullOrEmpty(Options.ProjectId)) - { - return Options.ProjectId; - } - var projectId = Options.Credential.ToServiceAccountCredential()?.ProjectId; - if (!string.IsNullOrEmpty(projectId)) - { - return projectId; - } - foreach (var variableName in new[] { "GOOGLE_CLOUD_PROJECT", "GCLOUD_PROJECT" }) - { - projectId = Environment.GetEnvironmentVariable(variableName); - if (!string.IsNullOrEmpty(projectId)) + FirebaseApp app; + if (Apps.TryGetValue(name, out app)) { - return projectId; + return app; } } return null; @@ -258,36 +202,35 @@ public static FirebaseApp Create(AppOptions options, string name) } } - private static AppOptions GetOptionsFromEnvironment() - { - return new AppOptions() - { - Credential = GoogleCredential.GetApplicationDefault(), - }; - } - /// - /// Returns the app instance identified by the given name. + /// Deletes this app instance and cleans up any state associated with it. Once an app has + /// been deleted, accessing any services related to it will result in an exception. + /// If the app is already deleted, this method is a no-op. /// - /// The instance with the specified name or null if it - /// doesn't exist. - /// If the name argument is null or empty. - /// Name of the app to retrieve. - public static FirebaseApp GetInstance(string name) + public void Delete() { - if (string.IsNullOrEmpty(name)) + // Clean up local state + lock (this.appLock) { - throw new ArgumentException("App name to lookup must not be null or empty"); + this.deleted = true; + foreach (var entry in this.services) + { + try + { + entry.Value.Delete(); + } + catch (Exception e) + { + Logger.Error(e, "Error while cleaning up service {0}", entry.Key); + } + } + this.services.Clear(); } + // Clean up global state lock (Apps) { - FirebaseApp app; - if (Apps.TryGetValue(name, out app)) - { - return app; - } + Apps.Remove(Name); } - return null; } /// @@ -308,5 +251,62 @@ internal static void DeleteAll() } } } + + internal T GetOrInit(string id, ServiceFactory initializer) + where T : class, IFirebaseService + { + lock (this.appLock) + { + if (this.deleted) + { + throw new InvalidOperationException("Cannot use an app after it has been deleted"); + } + IFirebaseService service; + if (!this.services.TryGetValue(id, out service)) + { + service = initializer(); + this.services.Add(id, service); + } + return (T)service; + } + } + + /// + /// Returns the Google Cloud Platform project ID associated with this Firebase app. If a + /// project ID is specified in , that value is returned. If not + /// attempts to determine a project ID from the used to + /// initialize the app. Looks up the GOOGLE_CLOUD_PROJECT environment variable when all + /// else fails. + /// + /// A project ID string or null. + internal string GetProjectId() + { + if (!string.IsNullOrEmpty(Options.ProjectId)) + { + return Options.ProjectId; + } + var projectId = Options.Credential.ToServiceAccountCredential()?.ProjectId; + if (!string.IsNullOrEmpty(projectId)) + { + return projectId; + } + foreach (var variableName in new[] { "GOOGLE_CLOUD_PROJECT", "GCLOUD_PROJECT" }) + { + projectId = Environment.GetEnvironmentVariable(variableName); + if (!string.IsNullOrEmpty(projectId)) + { + return projectId; + } + } + return null; + } + + private static AppOptions GetOptionsFromEnvironment() + { + return new AppOptions() + { + Credential = GoogleCredential.GetApplicationDefault(), + }; + } } } diff --git a/stylecop.ruleset b/stylecop.ruleset index 5f139441..ba9d2760 100644 --- a/stylecop.ruleset +++ b/stylecop.ruleset @@ -4,14 +4,9 @@ - - - - - - - - + + + diff --git a/stylecop_test.ruleset b/stylecop_test.ruleset index e78a40d5..9adea184 100644 --- a/stylecop_test.ruleset +++ b/stylecop_test.ruleset @@ -4,14 +4,9 @@ - - - - - - + From d16f67045e990265c0e5ed99d1f281e8be91e450 Mon Sep 17 00:00:00 2001 From: hiranya911 Date: Mon, 21 Jan 2019 16:03:55 -0800 Subject: [PATCH 05/13] Fixed more lint errors --- .../Auth/FirebaseAuthTest.cs | 2 +- .../Auth/FirebaseTokenFactoryTest.cs | 2 +- .../FirebaseAdmin.Tests/Auth/IAMSignerTest.cs | 8 +- .../FirebaseAdmin/Auth/FirebaseAuth.cs | 5 ++ .../FirebaseAdmin/Auth/FirebaseToken.cs | 21 ----- .../FirebaseAdmin/Auth/FirebaseTokenArgs.cs | 40 +++++++++ .../Auth/FirebaseTokenFactory.cs | 18 ++-- .../Auth/FirebaseTokenVerifier.cs | 22 ++--- .../Auth/FirebaseTokenVerifierArgs.cs | 35 ++++++++ .../Auth/FixedAccountIAMSigner.cs | 45 ++++++++++ .../FirebaseAdmin/Auth/HttpPublicKeySource.cs | 2 + FirebaseAdmin/FirebaseAdmin/Auth/IAMSigner.cs | 83 +++++++------------ FirebaseAdmin/FirebaseAdmin/Auth/JwtUtils.cs | 1 + .../Auth/ServiceAccountSigner.cs | 1 + FirebaseAdmin/FirebaseAdmin/Extensions.cs | 1 + FirebaseAdmin/FirebaseAdmin/FirebaseApp.cs | 20 ++++- stylecop.ruleset | 4 +- stylecop_test.ruleset | 4 +- 18 files changed, 204 insertions(+), 110 deletions(-) create mode 100644 FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenArgs.cs create mode 100644 FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenVerifierArgs.cs create mode 100644 FirebaseAdmin/FirebaseAdmin/Auth/FixedAccountIAMSigner.cs diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseAuthTest.cs b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseAuthTest.cs index 2740a250..9ff1d06f 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseAuthTest.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseAuthTest.cs @@ -151,7 +151,7 @@ private static void VerifyCustomToken(string token, string uid, Dictionary(segments[1]); + var payload = JwtUtils.Decode(segments[1]); Assert.Equal("client@test-project.iam.gserviceaccount.com", payload.Issuer); Assert.Equal("client@test-project.iam.gserviceaccount.com", payload.Subject); Assert.Equal(uid, payload.Uid); diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseTokenFactoryTest.cs b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseTokenFactoryTest.cs index c66051ef..8bafe5bd 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseTokenFactoryTest.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseTokenFactoryTest.cs @@ -102,7 +102,7 @@ private static void VerifyCustomToken( Assert.Equal("RS256", header.Algorithm); // verify payload - var payload = JwtUtils.Decode(segments[1]); + var payload = JwtUtils.Decode(segments[1]); Assert.Equal(MockSigner.KeyIdString, payload.Issuer); Assert.Equal(MockSigner.KeyIdString, payload.Subject); Assert.Equal(uid, payload.Uid); diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/IAMSignerTest.cs b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/IAMSignerTest.cs index ea72c041..3bd82579 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/IAMSignerTest.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/IAMSignerTest.cs @@ -46,14 +46,14 @@ public async Task Signer() Assert.Equal("discovered-service-account", await signer.GetKeyIdAsync()); Assert.Equal(1, handler.Calls); - handler.Response = new SignBlobResponse() + handler.Response = new IAMSigner.SignBlobResponse() { Signature = Convert.ToBase64String(bytes), }; byte[] data = Encoding.UTF8.GetBytes("Hello world"); byte[] signature = await signer.SignDataAsync(data); Assert.Equal(bytes, signature); - var req = NewtonsoftJsonSerializer.Instance.Deserialize( + var req = NewtonsoftJsonSerializer.Instance.Deserialize( handler.Request); Assert.Equal(Convert.ToBase64String(data), req.BytesToSign); Assert.Equal(2, handler.Calls); @@ -86,7 +86,7 @@ public async Task Signer() var bytes = Encoding.UTF8.GetBytes("signature"); var handler = new MockMessageHandler() { - Response = new SignBlobResponse() + Response = new IAMSigner.SignBlobResponse() { Signature = Convert.ToBase64String(bytes), }, @@ -98,7 +98,7 @@ public async Task Signer() byte[] data = Encoding.UTF8.GetBytes("Hello world"); byte[] signature = await signer.SignDataAsync(data); Assert.Equal(bytes, signature); - var req = NewtonsoftJsonSerializer.Instance.Deserialize( + var req = NewtonsoftJsonSerializer.Instance.Deserialize( handler.Request); Assert.Equal(Convert.ToBase64String(data), req.BytesToSign); Assert.Equal(1, handler.Calls); diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs index 275aae3f..4d5080dc 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs @@ -53,6 +53,7 @@ public static FirebaseAuth DefaultInstance { return null; } + return GetAuth(app); } } @@ -70,6 +71,7 @@ public static FirebaseAuth GetAuth(FirebaseApp app) { throw new ArgumentNullException("App argument must not be null."); } + return app.GetOrInit(typeof(FirebaseAuth).Name, () => { return new FirebaseAuth(app); @@ -213,8 +215,10 @@ public async Task CreateCustomTokenAsync( { throw new InvalidOperationException("Cannot invoke after deleting the app."); } + tokenFactory = this.tokenFactory.Value; } + return await tokenFactory.CreateCustomTokenAsync( uid, developerClaims, cancellationToken).ConfigureAwait(false); } @@ -268,6 +272,7 @@ public async Task VerifyIdTokenAsync( throw new InvalidOperationException("Cannot invoke after deleting the app."); } } + return await this.idTokenVerifier.Value.VerifyTokenAsync(idToken, cancellationToken) .ConfigureAwait(false); } diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseToken.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseToken.cs index 2e8487b6..c60d5339 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseToken.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseToken.cs @@ -71,25 +71,4 @@ internal FirebaseToken(FirebaseTokenArgs args) /// public IReadOnlyDictionary Claims { get; private set; } } - - internal sealed class FirebaseTokenArgs - { - [JsonProperty("iss")] - public string Issuer { get; set; } - - [JsonProperty("sub")] - public string Subject { get; set; } - - [JsonProperty("aud")] - public string Audience { get; set; } - - [JsonProperty("exp")] - public long ExpirationTimeSeconds { get; set; } - - [JsonProperty("iat")] - public long IssuedAtTimeSeconds { get; set; } - - [JsonIgnore] - public IReadOnlyDictionary Claims { get; set; } - } } diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenArgs.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenArgs.cs new file mode 100644 index 00000000..027feb6b --- /dev/null +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenArgs.cs @@ -0,0 +1,40 @@ +// Copyright 2018, Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace FirebaseAdmin.Auth +{ + internal sealed class FirebaseTokenArgs + { + [JsonProperty("iss")] + public string Issuer { get; set; } + + [JsonProperty("sub")] + public string Subject { get; set; } + + [JsonProperty("aud")] + public string Audience { get; set; } + + [JsonProperty("exp")] + public long ExpirationTimeSeconds { get; set; } + + [JsonProperty("iat")] + public long IssuedAtTimeSeconds { get; set; } + + [JsonIgnore] + public IReadOnlyDictionary Claims { get; set; } + } +} diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenFactory.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenFactory.cs index 4c0c1e43..ce6c85f2 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenFactory.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenFactory.cs @@ -93,6 +93,7 @@ public static FirebaseTokenFactory Create(FirebaseApp app) signer = new FixedAccountIAMSigner( new HttpClientFactory(), app.Options.Credential, app.Options.ServiceAccountId); } + return new FirebaseTokenFactory(signer, SystemClock.Default); } @@ -109,6 +110,7 @@ public async Task CreateCustomTokenAsync( { throw new ArgumentException("uid must not be longer than 128 characters"); } + if (developerClaims != null) { foreach (var entry in developerClaims) @@ -138,10 +140,12 @@ public async Task CreateCustomTokenAsync( IssuedAtTimeSeconds = issued, ExpirationTimeSeconds = issued + TokenDurationSeconds, }; + if (developerClaims != null && developerClaims.Count > 0) { payload.Claims = developerClaims; } + return await JwtUtils.CreateSignedJwtAsync( header, payload, this.signer, cancellationToken).ConfigureAwait(false); } @@ -150,14 +154,14 @@ public void Dispose() { signer.Dispose(); } - } - internal class CustomTokenPayload : JsonWebToken.Payload - { - [Newtonsoft.Json.JsonPropertyAttribute("uid")] - public string Uid { get; set; } + internal class CustomTokenPayload : JsonWebToken.Payload + { + [Newtonsoft.Json.JsonPropertyAttribute("uid")] + public string Uid { get; set; } - [Newtonsoft.Json.JsonPropertyAttribute("claims")] - public IDictionary Claims { get; set; } + [Newtonsoft.Json.JsonPropertyAttribute("claims")] + public IDictionary Claims { get; set; } + } } } diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenVerifier.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenVerifier.cs index 4bf18cf1..80529c83 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenVerifier.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenVerifier.cs @@ -81,6 +81,7 @@ internal static FirebaseTokenVerifier CreateIDTokenVerifier(FirebaseApp app) throw new ArgumentException( "Must initialize FirebaseApp with a project ID to verify ID tokens."); } + var keySource = new HttpPublicKeySource( IdTokenCertUrl, SystemClock.Default, new HttpClientFactory()); var args = new FirebaseTokenVerifierArgs() @@ -93,6 +94,7 @@ internal static FirebaseTokenVerifier CreateIDTokenVerifier(FirebaseApp app) Clock = SystemClock.Default, PublicKeySource = keySource, }; + return new FirebaseTokenVerifier(args); } @@ -103,6 +105,7 @@ internal async Task VerifyTokenAsync( { throw new ArgumentException($"{this.shortName} must not be null or empty."); } + string[] segments = token.Split('.'); if (segments.Length != 3) { @@ -179,6 +182,7 @@ await VerifySignatureAsync(segments, header.KeyId, cancellationToken) { allClaims.Remove(claim); } + payload.Claims = allClaims.ToImmutableDictionary(); return new FirebaseToken(payload); } @@ -204,6 +208,7 @@ private async Task VerifySignatureAsync( hash = hashAlg.ComputeHash( Encoding.ASCII.GetBytes($"{segments[0]}.{segments[1]}")); } + var signature = JwtUtils.Base64DecodeToBytes(segments[2]); var keys = await this.keySource.GetPublicKeysAsync(cancellationToken) .ConfigureAwait(false); @@ -224,21 +229,4 @@ private async Task VerifySignatureAsync( } } } - - internal sealed class FirebaseTokenVerifierArgs - { - public string ProjectId { get; set; } - - public string ShortName { get; set; } - - public string Operation { get; set; } - - public string Url { get; set; } - - public string Issuer { get; set; } - - public IClock Clock { get; set; } - - public IPublicKeySource PublicKeySource { get; set; } - } } diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenVerifierArgs.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenVerifierArgs.cs new file mode 100644 index 00000000..d79524b7 --- /dev/null +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenVerifierArgs.cs @@ -0,0 +1,35 @@ +// Copyright 2018, Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using Google.Apis.Util; + +namespace FirebaseAdmin.Auth +{ + internal sealed class FirebaseTokenVerifierArgs + { + public string ProjectId { get; set; } + + public string ShortName { get; set; } + + public string Operation { get; set; } + + public string Url { get; set; } + + public string Issuer { get; set; } + + public IClock Clock { get; set; } + + public IPublicKeySource PublicKeySource { get; set; } + } +} diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FixedAccountIAMSigner.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FixedAccountIAMSigner.cs new file mode 100644 index 00000000..92123bd2 --- /dev/null +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FixedAccountIAMSigner.cs @@ -0,0 +1,45 @@ +// Copyright 2018, Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System.Threading; +using System.Threading.Tasks; +using Google.Apis.Auth.OAuth2; +using Google.Apis.Http; +using Google.Apis.Util; + +namespace FirebaseAdmin.Auth +{ + /// + /// An implementation that uses the IAM service to sign data. Unlike + /// this class does not attempt to auto discover a service account ID. + /// Insterad it must be initialized with a fixed service account ID string. + /// + internal sealed class FixedAccountIAMSigner : IAMSigner + { + private readonly string keyId; + + public FixedAccountIAMSigner( + HttpClientFactory clientFactory, GoogleCredential credential, string keyId) + : base(clientFactory, credential) + { + this.keyId = keyId.ThrowIfNullOrEmpty(nameof(keyId)); + } + + public override Task GetKeyIdAsync( + CancellationToken cancellationToken = default(CancellationToken)) + { + return Task.FromResult(this.keyId); + } + } +} \ No newline at end of file diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/HttpPublicKeySource.cs b/FirebaseAdmin/FirebaseAdmin/Auth/HttpPublicKeySource.cs index 1efeb1c7..5becff23 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/HttpPublicKeySource.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/HttpPublicKeySource.cs @@ -112,6 +112,7 @@ private IReadOnlyList ParseKeys(string json) { throw new InvalidDataException("No public keys present in the response."); } + var builder = ImmutableList.CreateBuilder(); foreach (var entry in rawKeys) { @@ -126,6 +127,7 @@ private IReadOnlyList ParseKeys(string json) #endif builder.Add(new PublicKey(entry.Key, rsa)); } + return builder.ToImmutableList(); } } diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/IAMSigner.cs b/FirebaseAdmin/FirebaseAdmin/Auth/IAMSigner.cs index 2d8b283c..0057b3e2 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/IAMSigner.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/IAMSigner.cs @@ -60,6 +60,7 @@ public async Task SignDataAsync( { BytesToSign = Convert.ToBase64String(data), }; + try { var response = await httpClient.PostJsonAsync(url, request, cancellationToken) @@ -114,6 +115,7 @@ private void ThrowIfError(HttpResponseMessage response, string content) { return; } + string error = null; try { @@ -124,72 +126,51 @@ private void ThrowIfError(HttpResponseMessage response, string content) { // Ignore any errors encountered while parsing the originl error. } + if (string.IsNullOrEmpty(error)) { error = "Response status code does not indicate success: " + $"{(int)response.StatusCode} ({response.StatusCode})" + $"{Environment.NewLine}{content}"; } + throw new FirebaseException(error); } - } - - /// - /// Represents the sign request sent to the remote IAM service. - /// - internal class SignBlobRequest - { - [Newtonsoft.Json.JsonProperty("bytesToSign")] - public string BytesToSign { get; set; } - } - - /// - /// Represents the sign response sent by the remote IAM service. - /// - internal class SignBlobResponse - { - [Newtonsoft.Json.JsonProperty("signature")] - public string Signature { get; set; } - } - - /// - /// Represents an error response sent by the remote IAM service. - /// - internal class SignBlobError - { - [Newtonsoft.Json.JsonProperty("error")] - public SignBlobErrorDetail Error { get; set; } - } - /// - /// Represents the error details embedded in an IAM error response. - /// - internal class SignBlobErrorDetail - { - [Newtonsoft.Json.JsonProperty("message")] - public string Message { get; set; } - } + /// + /// Represents the sign request sent to the remote IAM service. + /// + internal class SignBlobRequest + { + [Newtonsoft.Json.JsonProperty("bytesToSign")] + public string BytesToSign { get; set; } + } - /// - /// An implementation that uses the IAM service to sign data. Unlike - /// this class does not attempt to auto discover a service account ID. - /// Insterad it must be initialized with a fixed service account ID string. - /// - internal sealed class FixedAccountIAMSigner : IAMSigner - { - private readonly string keyId; + /// + /// Represents the sign response sent by the remote IAM service. + /// + internal class SignBlobResponse + { + [Newtonsoft.Json.JsonProperty("signature")] + public string Signature { get; set; } + } - public FixedAccountIAMSigner( - HttpClientFactory clientFactory, GoogleCredential credential, string keyId) - : base(clientFactory, credential) + /// + /// Represents an error response sent by the remote IAM service. + /// + private class SignBlobError { - this.keyId = keyId.ThrowIfNullOrEmpty(nameof(keyId)); + [Newtonsoft.Json.JsonProperty("error")] + public SignBlobErrorDetail Error { get; set; } } - public override Task GetKeyIdAsync( - CancellationToken cancellationToken = default(CancellationToken)) + /// + /// Represents the error details embedded in an IAM error response. + /// + private class SignBlobErrorDetail { - return Task.FromResult(this.keyId); + [Newtonsoft.Json.JsonProperty("message")] + public string Message { get; set; } } } } \ No newline at end of file diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/JwtUtils.cs b/FirebaseAdmin/FirebaseAdmin/Auth/JwtUtils.cs index aabd62b0..b252236f 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/JwtUtils.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/JwtUtils.cs @@ -53,6 +53,7 @@ internal static byte[] Base64DecodeToBytes(string input) case 2: input += "=="; break; case 3: input += "="; break; } + return Convert.FromBase64String(input); } diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/ServiceAccountSigner.cs b/FirebaseAdmin/FirebaseAdmin/Auth/ServiceAccountSigner.cs index f47dc0ac..dc69f0c9 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/ServiceAccountSigner.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/ServiceAccountSigner.cs @@ -33,6 +33,7 @@ public ServiceAccountSigner(ServiceAccountCredential credential) { throw new ArgumentNullException("Credential must not be null."); } + this.credential = credential; } diff --git a/FirebaseAdmin/FirebaseAdmin/Extensions.cs b/FirebaseAdmin/FirebaseAdmin/Extensions.cs index b8a1d960..1eaa3590 100644 --- a/FirebaseAdmin/FirebaseAdmin/Extensions.cs +++ b/FirebaseAdmin/FirebaseAdmin/Extensions.cs @@ -41,6 +41,7 @@ public static ServiceAccountCredential ToServiceAccountCredential( return ((GoogleCredential)credential.UnderlyingCredential) .ToServiceAccountCredential(); } + return credential.UnderlyingCredential as ServiceAccountCredential; } diff --git a/FirebaseAdmin/FirebaseAdmin/FirebaseApp.cs b/FirebaseAdmin/FirebaseAdmin/FirebaseApp.cs index cee07c13..8ea5ad73 100644 --- a/FirebaseAdmin/FirebaseAdmin/FirebaseApp.cs +++ b/FirebaseAdmin/FirebaseAdmin/FirebaseApp.cs @@ -68,14 +68,16 @@ public sealed class FirebaseApp private FirebaseApp(AppOptions options, string name) { this.options = new AppOptions(options); - if (options.Credential == null) + if (this.options.Credential == null) { throw new ArgumentNullException("Credential must be set"); } - if (options.Credential.IsCreateScopedRequired) + + if (this.options.Credential.IsCreateScopedRequired) { - options.Credential = options.Credential.CreateScoped(DefaultScopes); + this.options.Credential = this.options.Credential.CreateScoped(DefaultScopes); } + Name = name; } @@ -120,6 +122,7 @@ public static FirebaseApp GetInstance(string name) { throw new ArgumentException("App name to lookup must not be null or empty"); } + lock (Apps) { FirebaseApp app; @@ -128,6 +131,7 @@ public static FirebaseApp GetInstance(string name) return app; } } + return null; } @@ -182,6 +186,7 @@ public static FirebaseApp Create(AppOptions options, string name) { throw new ArgumentException("App name must not be null or empty"); } + options = options ?? GetOptionsFromEnvironment(); lock (Apps) { @@ -196,6 +201,7 @@ public static FirebaseApp Create(AppOptions options, string name) throw new ArgumentException($"FirebaseApp named {name} already exists."); } } + var app = new FirebaseApp(options, name); Apps.Add(name, app); return app; @@ -224,8 +230,10 @@ public void Delete() Logger.Error(e, "Error while cleaning up service {0}", entry.Key); } } + this.services.Clear(); } + // Clean up global state lock (Apps) { @@ -245,6 +253,7 @@ internal static void DeleteAll() { entry.Value.Delete(); } + if (Apps.Count > 0) { throw new InvalidOperationException("Failed to delete all apps"); @@ -261,12 +270,14 @@ internal T GetOrInit(string id, ServiceFactory initializer) { throw new InvalidOperationException("Cannot use an app after it has been deleted"); } + IFirebaseService service; if (!this.services.TryGetValue(id, out service)) { service = initializer(); this.services.Add(id, service); } + return (T)service; } } @@ -285,11 +296,13 @@ internal string GetProjectId() { return Options.ProjectId; } + var projectId = Options.Credential.ToServiceAccountCredential()?.ProjectId; if (!string.IsNullOrEmpty(projectId)) { return projectId; } + foreach (var variableName in new[] { "GOOGLE_CLOUD_PROJECT", "GCLOUD_PROJECT" }) { projectId = Environment.GetEnvironmentVariable(variableName); @@ -298,6 +311,7 @@ internal string GetProjectId() return projectId; } } + return null; } diff --git a/stylecop.ruleset b/stylecop.ruleset index ba9d2760..a012047b 100644 --- a/stylecop.ruleset +++ b/stylecop.ruleset @@ -6,10 +6,8 @@ + - - - diff --git a/stylecop_test.ruleset b/stylecop_test.ruleset index 9adea184..95fa5539 100644 --- a/stylecop_test.ruleset +++ b/stylecop_test.ruleset @@ -6,9 +6,9 @@ + + - - From f99154935b55896899b3559b4e4cd85daa330e7e Mon Sep 17 00:00:00 2001 From: hiranya911 Date: Mon, 21 Jan 2019 16:29:17 -0800 Subject: [PATCH 06/13] Fixed almost everything --- .../Auth/FirebaseTokenFactoryTest.cs | 1 + .../Auth/FirebaseTokenVerifierTest.cs | 2 ++ .../FirebaseAdmin.Tests/MockMessageHandler.cs | 3 +++ FirebaseAdmin/FirebaseAdmin/AppOptions.cs | 10 +++++---- .../FirebaseAdmin/Auth/FirebaseAuth.cs | 2 +- .../FirebaseAdmin/Auth/FirebaseToken.cs | 16 +++++++------- .../Auth/FirebaseTokenVerifier.cs | 1 + FirebaseAdmin/FirebaseAdmin/Auth/PublicKey.cs | 4 ++-- FirebaseAdmin/FirebaseAdmin/Extensions.cs | 21 +++++++++++++++++++ FirebaseAdmin/FirebaseAdmin/FirebaseApp.cs | 6 +++--- stylecop.ruleset | 10 ++------- stylecop_test.ruleset | 20 +++++++----------- 12 files changed, 59 insertions(+), 37 deletions(-) diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseTokenFactoryTest.cs b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseTokenFactoryTest.cs index 8bafe5bd..fa954b82 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseTokenFactoryTest.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseTokenFactoryTest.cs @@ -96,6 +96,7 @@ private static void VerifyCustomToken( { string[] segments = token.Split("."); Assert.Equal(3, segments.Length); + // verify header var header = JwtUtils.Decode(segments[0]); Assert.Equal("JWT", header.Type); diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseTokenVerifierTest.cs b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseTokenVerifierTest.cs index 8d45232e..306d3b5b 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseTokenVerifierTest.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseTokenVerifierTest.cs @@ -64,6 +64,7 @@ public async Task ValidToken() Assert.Equal("testuser", decoded.Uid); Assert.Equal("test-project", decoded.Audience); Assert.Equal("testuser", decoded.Subject); + // The default test token created by CreateTestTokenAsync has an issue time 10 minutes // ago, and an expiry time 50 minutes in the future. Assert.Equal(Clock.UnixTimestamp() - (60 * 10), decoded.IssuedAtTimeSeconds); @@ -283,6 +284,7 @@ internal static async Task CreateTestTokenAsync( payload[entry.Key] = entry.Value; } } + return await JwtUtils.CreateSignedJwtAsync(header, payload, Signer); } diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/MockMessageHandler.cs b/FirebaseAdmin/FirebaseAdmin.Tests/MockMessageHandler.cs index ebd34534..117c888a 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/MockMessageHandler.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/MockMessageHandler.cs @@ -58,6 +58,7 @@ protected override async Task SendAsyncCore( { Request = null; } + var resp = new HttpResponseMessage(); string json; if (Response is byte[]) @@ -72,11 +73,13 @@ protected override async Task SendAsyncCore( { json = NewtonsoftJsonSerializer.Instance.Serialize(Response); } + resp.StatusCode = StatusCode; if (ApplyHeaders != null) { ApplyHeaders(resp.Headers); } + resp.Content = new StringContent(json, Encoding.UTF8, "application/json"); var tcs = new TaskCompletionSource(); tcs.SetResult(resp); diff --git a/FirebaseAdmin/FirebaseAdmin/AppOptions.cs b/FirebaseAdmin/FirebaseAdmin/AppOptions.cs index 1a4bf78f..045d9e9d 100644 --- a/FirebaseAdmin/FirebaseAdmin/AppOptions.cs +++ b/FirebaseAdmin/FirebaseAdmin/AppOptions.cs @@ -38,18 +38,20 @@ internal AppOptions(AppOptions options) } /// - /// used to authorize an app. All service calls made by - /// the app will be authorized using this. + /// Gets or sets the used to authorize an app. All service + /// calls made by the app will be authorized using this. /// public GoogleCredential Credential { get; set; } /// - /// The Google Cloud Platform project ID that should be associated with an app. + /// Gets or sets the Google Cloud Platform project ID that should be associated with an + /// app. /// public string ProjectId { get; set; } /// - /// The unique ID of the service account that should be associated with an app. + /// Gets or sets the unique ID of the service account that should be associated with an + /// app. /// This is used to /// create custom auth tokens when service account credentials are not available. The /// service account ID can be found in the client_email field of the service account diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs index 4d5080dc..8b88977a 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs @@ -41,7 +41,7 @@ private FirebaseAuth(FirebaseApp app) } /// - /// The auth instance associated with the default Firebase app. This property is + /// Gets the auth instance associated with the default Firebase app. This property is /// null if the default app doesn't yet exist. /// public static FirebaseAuth DefaultInstance diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseToken.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseToken.cs index c60d5339..d4fc1659 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseToken.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseToken.cs @@ -35,38 +35,40 @@ internal FirebaseToken(FirebaseTokenArgs args) } /// - /// The issuer claim that identifies the principal that issued the JWT. + /// Gets the issuer claim that identifies the principal that issued the JWT. /// public string Issuer { get; private set; } /// - /// The subject claim identifying the principal that is the subject of the JWT. + /// Gets the subject claim identifying the principal that is the subject of the JWT. /// public string Subject { get; private set; } /// - /// The audience claim that identifies the audience that the JWT is intended for. + /// Gets the audience claim that identifies the audience that the JWT is intended for. /// public string Audience { get; private set; } /// - /// The expiration time claim that identifies the expiration time (in seconds) + /// Gets the expiration time claim that identifies the expiration time (in seconds) /// on or after which the token MUST NOT be accepted for processing. /// public long ExpirationTimeSeconds { get; private set; } /// - /// The issued at claim that identifies the time (in seconds) at which the JWT was issued. + /// Gets the issued at claim that identifies the time (in seconds) at which the JWT was + /// issued. /// public long IssuedAtTimeSeconds { get; private set; } /// - /// User ID of the user to which this ID token belongs. This is same as Subject. + /// Gets the User ID of the user to which this ID token belongs. This is same as + /// . /// public string Uid { get; private set; } /// - /// A read-only dictionary of all other claims present in the JWT. This can be used to + /// Gets Aall other claims present in the JWT as a readonly dictionary. This can be used to /// access custom claims of the token. /// public IReadOnlyDictionary Claims { get; private set; } diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenVerifier.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenVerifier.cs index 80529c83..ecb7ed00 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenVerifier.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenVerifier.cs @@ -177,6 +177,7 @@ internal async Task VerifyTokenAsync( await VerifySignatureAsync(segments, header.KeyId, cancellationToken) .ConfigureAwait(false); var allClaims = JwtUtils.Decode>(segments[1]); + // Remove standard claims, so that only custom claims would remain. foreach (var claim in StandardClaims) { diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/PublicKey.cs b/FirebaseAdmin/FirebaseAdmin/Auth/PublicKey.cs index a29f05a4..280cb53e 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/PublicKey.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/PublicKey.cs @@ -34,12 +34,12 @@ public PublicKey(string keyId, RSAKey rsa) } /// - /// The unique identifier of this key. + /// Gets the unique identifier of this key. /// public string Id { get; } /// - /// A instance containing the contents of + /// Gets the instance containing the contents of /// the public key. /// public RSAKey RSA { get; } diff --git a/FirebaseAdmin/FirebaseAdmin/Extensions.cs b/FirebaseAdmin/FirebaseAdmin/Extensions.cs index 1eaa3590..650db9df 100644 --- a/FirebaseAdmin/FirebaseAdmin/Extensions.cs +++ b/FirebaseAdmin/FirebaseAdmin/Extensions.cs @@ -33,6 +33,9 @@ internal static class Extensions /// . Returns null if the GoogleCredential is not /// based on a service account. /// + /// A service account credential if available, or null. + /// The Google credential from which to extract service account + /// credentials. public static ServiceAccountCredential ToServiceAccountCredential( this GoogleCredential credential) { @@ -49,6 +52,9 @@ public static ServiceAccountCredential ToServiceAccountCredential( /// Creates a default (unauthenticated) from the /// factory. /// + /// An HTTP client that can be used to make unauthenticated requests. + /// The used to create + /// the HTTP client. public static ConfigurableHttpClient CreateDefaultHttpClient( this HttpClientFactory clientFactory) { @@ -59,6 +65,11 @@ public static ConfigurableHttpClient CreateDefaultHttpClient( /// Creates an authenticated from the /// factory. /// + /// An HTTP client that can be used to OAuth2 authorized requests. + /// The used to create + /// the HTTP client. + /// The Google credential that will be used to authenticate + /// outgoing HTTP requests. public static ConfigurableHttpClient CreateAuthorizedHttpClient( this HttpClientFactory clientFactory, GoogleCredential credential) { @@ -70,6 +81,14 @@ public static ConfigurableHttpClient CreateAuthorizedHttpClient( /// /// Makes a JSON POST request using the given parameters. /// + /// An representing the response to the + /// POST request. + /// Type of the object that will be serialized into JSON. + /// The used to make the request. + /// URI for the outgoing request. + /// The object that will be serialized as the JSON body. + /// A cancellation token to monitor the asynchronous + /// operation. public static async Task PostJsonAsync( this HttpClient client, string requestUri, T body, CancellationToken cancellationToken) { @@ -82,6 +101,8 @@ public static async Task PostJsonAsync( /// /// Returns a Unix-styled timestamp (seconds from epoch) from the . /// + /// Number of seconds since epoch. + /// The used to generate the timestamp. public static long UnixTimestamp(this IClock clock) { var timeSinceEpoch = clock.UtcNow.Subtract(new DateTime(1970, 1, 1)); diff --git a/FirebaseAdmin/FirebaseAdmin/FirebaseApp.cs b/FirebaseAdmin/FirebaseAdmin/FirebaseApp.cs index 8ea5ad73..609f68f2 100644 --- a/FirebaseAdmin/FirebaseAdmin/FirebaseApp.cs +++ b/FirebaseAdmin/FirebaseAdmin/FirebaseApp.cs @@ -82,7 +82,7 @@ private FirebaseApp(AppOptions options, string name) } /// - /// The default app instance. This property is null if the default app instance + /// Gets the default app instance. This property is null if the default app instance /// doesn't yet exist. /// public static FirebaseApp DefaultInstance @@ -94,7 +94,7 @@ public static FirebaseApp DefaultInstance } /// - /// A copy of the this app was created with. + /// Gets a copy of the this app was created with. /// public AppOptions Options { @@ -105,7 +105,7 @@ public AppOptions Options } /// - /// Name of this app. + /// Gets the name of this app. /// public string Name { get; } diff --git a/stylecop.ruleset b/stylecop.ruleset index a012047b..4b810243 100644 --- a/stylecop.ruleset +++ b/stylecop.ruleset @@ -7,13 +7,7 @@ - - - - - - - - + + \ No newline at end of file diff --git a/stylecop_test.ruleset b/stylecop_test.ruleset index 95fa5539..7593a30c 100644 --- a/stylecop_test.ruleset +++ b/stylecop_test.ruleset @@ -4,19 +4,15 @@ - - + + - - - - - - - - - - + + + + + + \ No newline at end of file From 6bcc4d6231ff93d57a237386598e61badb552436 Mon Sep 17 00:00:00 2001 From: hiranya911 Date: Mon, 21 Jan 2019 16:33:01 -0800 Subject: [PATCH 07/13] Linter test commit --- .travis.yml | 1 + stylecop.ruleset | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 06088137..cf183702 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,4 +8,5 @@ matrix: script: - dotnet build FirebaseAdmin/FirebaseAdmin - dotnet build FirebaseAdmin/FirebaseAdmin.Snippets + - dotnet build FirebaseAdmin/FirebaseAdmin.IntegrationTests - dotnet test FirebaseAdmin/FirebaseAdmin.Tests diff --git a/stylecop.ruleset b/stylecop.ruleset index 4b810243..da07239c 100644 --- a/stylecop.ruleset +++ b/stylecop.ruleset @@ -6,7 +6,7 @@ - + From 9108c266a2b5aa54e416a7d50469f45834c570b8 Mon Sep 17 00:00:00 2001 From: hiranya911 Date: Mon, 21 Jan 2019 16:37:47 -0800 Subject: [PATCH 08/13] Fixing lint error --- stylecop.ruleset | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stylecop.ruleset b/stylecop.ruleset index da07239c..4b810243 100644 --- a/stylecop.ruleset +++ b/stylecop.ruleset @@ -6,7 +6,7 @@ - + From 1b9558aedf6a1af626413c2f1f4c6218901b1ce7 Mon Sep 17 00:00:00 2001 From: hiranya911 Date: Mon, 21 Jan 2019 19:51:53 -0800 Subject: [PATCH 09/13] Enabled lint rule for 'this' checks --- .../Auth/ServiceAccountSignerTest.cs | 2 +- .../FirebaseAdmin.Tests/FirebaseAppTest.cs | 2 +- .../FirebaseAdmin.Tests/MockClock.cs | 6 ++--- .../FirebaseAdmin.Tests/MockMessageHandler.cs | 24 +++++++++---------- FirebaseAdmin/FirebaseAdmin/AppOptions.cs | 6 ++--- .../FirebaseAdmin/Auth/FirebaseAuth.cs | 8 +++---- .../FirebaseAdmin/Auth/FirebaseToken.cs | 14 +++++------ .../Auth/FirebaseTokenFactory.cs | 2 +- .../Auth/FirebaseTokenVerifier.cs | 13 ++++------ .../FirebaseAdmin/Auth/HttpPublicKeySource.cs | 20 ++++++++-------- FirebaseAdmin/FirebaseAdmin/Auth/IAMSigner.cs | 10 ++++---- FirebaseAdmin/FirebaseAdmin/Auth/PublicKey.cs | 4 ++-- .../Auth/ServiceAccountSigner.cs | 12 ++++------ FirebaseAdmin/FirebaseAdmin/FirebaseApp.cs | 10 ++++---- stylecop.ruleset | 1 - stylecop_test.ruleset | 1 - 16 files changed, 63 insertions(+), 72 deletions(-) diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/ServiceAccountSignerTest.cs b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/ServiceAccountSignerTest.cs index ab51c2a1..cf76f125 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/ServiceAccountSignerTest.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/ServiceAccountSignerTest.cs @@ -36,7 +36,7 @@ public async Task Signer() "client@test-project.iam.gserviceaccount.com", await signer.GetKeyIdAsync()); byte[] data = Encoding.UTF8.GetBytes("Hello world"); byte[] signature = signer.SignDataAsync(data).Result; - Assert.True(Verify(data, signature)); + Assert.True(this.Verify(data, signature)); } [Fact] diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/FirebaseAppTest.cs b/FirebaseAdmin/FirebaseAdmin.Tests/FirebaseAppTest.cs index 1b7307a9..5a453821 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/FirebaseAppTest.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/FirebaseAppTest.cs @@ -222,7 +222,7 @@ internal class MockService : IFirebaseService public void Delete() { - Deleted = true; + this.Deleted = true; } } diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/MockClock.cs b/FirebaseAdmin/FirebaseAdmin.Tests/MockClock.cs index 3d26ca34..f68f7785 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/MockClock.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/MockClock.cs @@ -24,13 +24,13 @@ public class MockClock : IClock public MockClock() { - Now = DateTime.Now; + this.Now = DateTime.Now; } public DateTime Now { - get { return UtcNow.ToLocalTime(); } - set { UtcNow = value.ToUniversalTime(); } + get { return this.UtcNow.ToLocalTime(); } + set { this.UtcNow = value.ToUniversalTime(); } } public DateTime UtcNow diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/MockMessageHandler.cs b/FirebaseAdmin/FirebaseAdmin.Tests/MockMessageHandler.cs index 117c888a..b6456e79 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/MockMessageHandler.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/MockMessageHandler.cs @@ -34,7 +34,7 @@ internal class MockMessageHandler : CountableMessageHandler { public MockMessageHandler() { - StatusCode = HttpStatusCode.OK; + this.StatusCode = HttpStatusCode.OK; } public delegate void SetHeaders(HttpResponseHeaders header); @@ -52,32 +52,32 @@ protected override async Task SendAsyncCore( { if (request.Content != null) { - Request = await request.Content.ReadAsStringAsync(); + this.Request = await request.Content.ReadAsStringAsync(); } else { - Request = null; + this.Request = null; } var resp = new HttpResponseMessage(); string json; - if (Response is byte[]) + if (this.Response is byte[]) { - json = Encoding.UTF8.GetString(Response as byte[]); + json = Encoding.UTF8.GetString(this.Response as byte[]); } - else if (Response is string) + else if (this.Response is string) { - json = Response as string; + json = this.Response as string; } else { - json = NewtonsoftJsonSerializer.Instance.Serialize(Response); + json = NewtonsoftJsonSerializer.Instance.Serialize(this.Response); } - resp.StatusCode = StatusCode; - if (ApplyHeaders != null) + resp.StatusCode = this.StatusCode; + if (this.ApplyHeaders != null) { - ApplyHeaders(resp.Headers); + this.ApplyHeaders(resp.Headers); } resp.Content = new StringContent(json, Encoding.UTF8, "application/json"); @@ -104,7 +104,7 @@ protected sealed override Task SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) { Interlocked.Increment(ref this.calls); - return SendAsyncCore(request, cancellationToken); + return this.SendAsyncCore(request, cancellationToken); } protected abstract Task SendAsyncCore( diff --git a/FirebaseAdmin/FirebaseAdmin/AppOptions.cs b/FirebaseAdmin/FirebaseAdmin/AppOptions.cs index 045d9e9d..9d529ac5 100644 --- a/FirebaseAdmin/FirebaseAdmin/AppOptions.cs +++ b/FirebaseAdmin/FirebaseAdmin/AppOptions.cs @@ -32,9 +32,9 @@ public AppOptions() { } internal AppOptions(AppOptions options) { - Credential = options.Credential; - ProjectId = options.ProjectId; - ServiceAccountId = options.ServiceAccountId; + this.Credential = options.Credential; + this.ProjectId = options.ProjectId; + this.ServiceAccountId = options.ServiceAccountId; } /// diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs index 8b88977a..a2226a04 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs @@ -111,7 +111,7 @@ public static FirebaseAuth GetAuth(FirebaseApp app) /// 128 characters. public async Task CreateCustomTokenAsync(string uid) { - return await CreateCustomTokenAsync(uid, default(CancellationToken)); + return await this.CreateCustomTokenAsync(uid, default(CancellationToken)); } /// @@ -150,7 +150,7 @@ public async Task CreateCustomTokenAsync(string uid) public async Task CreateCustomTokenAsync( string uid, CancellationToken cancellationToken) { - return await CreateCustomTokenAsync(uid, null, cancellationToken); + return await this.CreateCustomTokenAsync(uid, null, cancellationToken); } /// @@ -177,7 +177,7 @@ public async Task CreateCustomTokenAsync( public async Task CreateCustomTokenAsync( string uid, IDictionary developerClaims) { - return await CreateCustomTokenAsync(uid, developerClaims, default(CancellationToken)); + return await this.CreateCustomTokenAsync(uid, developerClaims, default(CancellationToken)); } /// @@ -241,7 +241,7 @@ public async Task CreateCustomTokenAsync( /// A Firebase ID token string to parse and verify. public async Task VerifyIdTokenAsync(string idToken) { - return await VerifyIdTokenAsync(idToken, default(CancellationToken)); + return await this.VerifyIdTokenAsync(idToken, default(CancellationToken)); } /// diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseToken.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseToken.cs index d4fc1659..9cd4cc23 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseToken.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseToken.cs @@ -25,13 +25,13 @@ public sealed class FirebaseToken { internal FirebaseToken(FirebaseTokenArgs args) { - Issuer = args.Issuer; - Subject = args.Subject; - Audience = args.Audience; - ExpirationTimeSeconds = args.ExpirationTimeSeconds; - IssuedAtTimeSeconds = args.IssuedAtTimeSeconds; - Uid = args.Subject; - Claims = args.Claims; + this.Issuer = args.Issuer; + this.Subject = args.Subject; + this.Audience = args.Audience; + this.ExpirationTimeSeconds = args.ExpirationTimeSeconds; + this.IssuedAtTimeSeconds = args.IssuedAtTimeSeconds; + this.Uid = args.Subject; + this.Claims = args.Claims; } /// diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenFactory.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenFactory.cs index ce6c85f2..411c97fa 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenFactory.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenFactory.cs @@ -152,7 +152,7 @@ public async Task CreateCustomTokenAsync( public void Dispose() { - signer.Dispose(); + this.signer.Dispose(); } internal class CustomTokenPayload : JsonWebToken.Payload diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenVerifier.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenVerifier.cs index ecb7ed00..fc9fc1b6 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenVerifier.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenVerifier.cs @@ -38,9 +38,6 @@ internal sealed class FirebaseTokenVerifier private const string FirebaseAudience = "https://identitytoolkit.googleapis.com/" + "google.identity.identitytoolkit.v1.IdentityToolkit"; - // See http://oid-info.com/get/2.16.840.1.101.3.4.2.1 - private const string Sha256Oid = "2.16.840.1.101.3.4.2.1"; - private static readonly IReadOnlyList StandardClaims = ImmutableList.Create("iss", "aud", "exp", "iat", "sub", "uid"); @@ -54,7 +51,7 @@ internal sealed class FirebaseTokenVerifier internal FirebaseTokenVerifier(FirebaseTokenVerifierArgs args) { - ProjectId = args.ProjectId.ThrowIfNullOrEmpty(nameof(args.ProjectId)); + this.ProjectId = args.ProjectId.ThrowIfNullOrEmpty(nameof(args.ProjectId)); this.shortName = args.ShortName.ThrowIfNullOrEmpty(nameof(args.ShortName)); this.operation = args.Operation.ThrowIfNullOrEmpty(nameof(args.Operation)); this.url = args.Url.ThrowIfNullOrEmpty(nameof(args.Url)); @@ -118,7 +115,7 @@ internal async Task VerifyTokenAsync( + "project as the credential used to initialize this SDK."; var verifyTokenMessage = $"See {this.url} for details on how to retrieve a value " + $"{this.shortName}."; - var issuer = this.issuer + ProjectId; + var issuer = this.issuer + this.ProjectId; string error = null; if (string.IsNullOrEmpty(header.KeyId)) { @@ -142,9 +139,9 @@ internal async Task VerifyTokenAsync( error = $"Firebase {this.shortName} has incorrect algorithm. Expected RS256 but got " + $"{header.Algorithm}. {verifyTokenMessage}"; } - else if (ProjectId != payload.Audience) + else if (this.ProjectId != payload.Audience) { - error = $"{this.shortName} has incorrect audience (aud) claim. Expected {ProjectId} " + error = $"{this.shortName} has incorrect audience (aud) claim. Expected {this.ProjectId} " + $"but got {payload.Audience}. {projectIdMessage} {verifyTokenMessage}"; } else if (payload.Issuer != issuer) @@ -174,7 +171,7 @@ internal async Task VerifyTokenAsync( throw new FirebaseException(error); } - await VerifySignatureAsync(segments, header.KeyId, cancellationToken) + await this.VerifySignatureAsync(segments, header.KeyId, cancellationToken) .ConfigureAwait(false); var allClaims = JwtUtils.Decode>(segments[1]); diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/HttpPublicKeySource.cs b/FirebaseAdmin/FirebaseAdmin/Auth/HttpPublicKeySource.cs index 5becff23..6851d190 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/HttpPublicKeySource.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/HttpPublicKeySource.cs @@ -66,26 +66,26 @@ public HttpPublicKeySource(string certUrl, IClock clock, HttpClientFactory clien public async Task> GetPublicKeysAsync( CancellationToken cancellationToken = default(CancellationToken)) { - if (cachedKeys == null || clock.UtcNow >= expirationTime) + if (this.cachedKeys == null || this.clock.UtcNow >= this.expirationTime) { - await cacheLock.WaitAsync(cancellationToken).ConfigureAwait(false); + await this.cacheLock.WaitAsync(cancellationToken).ConfigureAwait(false); try { - var now = clock.UtcNow; - if (cachedKeys == null || now >= expirationTime) + var now = this.clock.UtcNow; + if (this.cachedKeys == null || now >= this.expirationTime) { - using (var httpClient = clientFactory.CreateDefaultHttpClient()) + using (var httpClient = this.clientFactory.CreateDefaultHttpClient()) { - var response = await httpClient.GetAsync(certUrl, cancellationToken) + var response = await httpClient.GetAsync(this.certUrl, cancellationToken) .ConfigureAwait(false); response.EnsureSuccessStatusCode(); - cachedKeys = ParseKeys(await response.Content.ReadAsStringAsync() + this.cachedKeys = this.ParseKeys(await response.Content.ReadAsStringAsync() .ConfigureAwait(false)); var cacheControl = response.Headers.CacheControl; if (cacheControl?.MaxAge != null) { - expirationTime = now.Add(cacheControl.MaxAge.Value) + this.expirationTime = now.Add(cacheControl.MaxAge.Value) .Subtract(ClockSkew); } } @@ -97,11 +97,11 @@ public async Task> GetPublicKeysAsync( } finally { - cacheLock.Release(); + this.cacheLock.Release(); } } - return cachedKeys; + return this.cachedKeys; } private IReadOnlyList ParseKeys(string json) diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/IAMSigner.cs b/FirebaseAdmin/FirebaseAdmin/Auth/IAMSigner.cs index 0057b3e2..9051c343 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/IAMSigner.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/IAMSigner.cs @@ -54,7 +54,7 @@ public IAMSigner(HttpClientFactory clientFactory, GoogleCredential credential) public async Task SignDataAsync( byte[] data, CancellationToken cancellationToken = default(CancellationToken)) { - var keyId = await GetKeyIdAsync(cancellationToken).ConfigureAwait(false); + var keyId = await this.GetKeyIdAsync(cancellationToken).ConfigureAwait(false); var url = string.Format(SignBlobUrl, keyId); var request = new SignBlobRequest { @@ -63,10 +63,10 @@ public async Task SignDataAsync( try { - var response = await httpClient.PostJsonAsync(url, request, cancellationToken) + var response = await this.httpClient.PostJsonAsync(url, request, cancellationToken) .ConfigureAwait(false); var json = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - ThrowIfError(response, json); + this.ThrowIfError(response, json); var parsed = NewtonsoftJsonSerializer.Instance.Deserialize(json); return Convert.FromBase64String(parsed.Signature); } @@ -81,7 +81,7 @@ public virtual async Task GetKeyIdAsync( { try { - return await keyId.Value.ConfigureAwait(false); + return await this.keyId.Value.ConfigureAwait(false); } catch (Exception e) { @@ -96,7 +96,7 @@ public virtual async Task GetKeyIdAsync( public void Dispose() { - httpClient.Dispose(); + this.httpClient.Dispose(); } private static async Task DiscoverServiceAccountIdAsync( diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/PublicKey.cs b/FirebaseAdmin/FirebaseAdmin/Auth/PublicKey.cs index 280cb53e..483f5f7c 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/PublicKey.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/PublicKey.cs @@ -29,8 +29,8 @@ internal sealed class PublicKey { public PublicKey(string keyId, RSAKey rsa) { - Id = keyId; - RSA = rsa; + this.Id = keyId; + this.RSA = rsa; } /// diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/ServiceAccountSigner.cs b/FirebaseAdmin/FirebaseAdmin/Auth/ServiceAccountSigner.cs index dc69f0c9..79b782e7 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/ServiceAccountSigner.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/ServiceAccountSigner.cs @@ -16,6 +16,7 @@ using System.Threading; using System.Threading.Tasks; using Google.Apis.Auth.OAuth2; +using Google.Apis.Util; namespace FirebaseAdmin.Auth { @@ -29,23 +30,18 @@ internal sealed class ServiceAccountSigner : ISigner public ServiceAccountSigner(ServiceAccountCredential credential) { - if (credential == null) - { - throw new ArgumentNullException("Credential must not be null."); - } - - this.credential = credential; + this.credential = credential.ThrowIfNull(nameof(credential)); } public Task GetKeyIdAsync(CancellationToken cancellationToken = default(CancellationToken)) { - return Task.FromResult(credential.Id); + return Task.FromResult(this.credential.Id); } public Task SignDataAsync(byte[] data, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); - var signature = credential.CreateSignature(data); + var signature = this.credential.CreateSignature(data); return Task.FromResult(Convert.FromBase64String(signature)); } diff --git a/FirebaseAdmin/FirebaseAdmin/FirebaseApp.cs b/FirebaseAdmin/FirebaseAdmin/FirebaseApp.cs index 609f68f2..9f12ecd2 100644 --- a/FirebaseAdmin/FirebaseAdmin/FirebaseApp.cs +++ b/FirebaseAdmin/FirebaseAdmin/FirebaseApp.cs @@ -78,7 +78,7 @@ private FirebaseApp(AppOptions options, string name) this.options.Credential = this.options.Credential.CreateScoped(DefaultScopes); } - Name = name; + this.Name = name; } /// @@ -237,7 +237,7 @@ public void Delete() // Clean up global state lock (Apps) { - Apps.Remove(Name); + Apps.Remove(this.Name); } } @@ -292,12 +292,12 @@ internal T GetOrInit(string id, ServiceFactory initializer) /// A project ID string or null. internal string GetProjectId() { - if (!string.IsNullOrEmpty(Options.ProjectId)) + if (!string.IsNullOrEmpty(this.Options.ProjectId)) { - return Options.ProjectId; + return this.Options.ProjectId; } - var projectId = Options.Credential.ToServiceAccountCredential()?.ProjectId; + var projectId = this.Options.Credential.ToServiceAccountCredential()?.ProjectId; if (!string.IsNullOrEmpty(projectId)) { return projectId; diff --git a/stylecop.ruleset b/stylecop.ruleset index 4b810243..fe083603 100644 --- a/stylecop.ruleset +++ b/stylecop.ruleset @@ -4,7 +4,6 @@ - diff --git a/stylecop_test.ruleset b/stylecop_test.ruleset index 7593a30c..eb44502a 100644 --- a/stylecop_test.ruleset +++ b/stylecop_test.ruleset @@ -4,7 +4,6 @@ - From 477ecd08fbc0772e1af9be1a6951aee89b3add2d Mon Sep 17 00:00:00 2001 From: hiranya911 Date: Mon, 21 Jan 2019 22:06:42 -0800 Subject: [PATCH 10/13] Enabled all possible rules; Added linting to snippets; --- .../FirebaseAdmin.IntegrationTests.csproj | 1 - .../FirebaseAdmin.Snippets.csproj | 5 +++++ .../FirebaseAppSnippets.cs | 16 ++++++++-------- .../FirebaseAuthSnippets.cs | 8 ++++---- .../FirebaseAdmin.Tests.csproj | 1 - FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs | 3 +++ FirebaseAdmin/FirebaseAdmin/FirebaseAdmin.csproj | 1 + FirebaseAdmin/FirebaseAdmin/IFirebaseService.cs | 3 +++ stylecop.json | 8 ++++++++ stylecop.ruleset | 1 - stylecop_test.ruleset | 3 +++ 11 files changed, 35 insertions(+), 15 deletions(-) create mode 100644 stylecop.json diff --git a/FirebaseAdmin/FirebaseAdmin.IntegrationTests/FirebaseAdmin.IntegrationTests.csproj b/FirebaseAdmin/FirebaseAdmin.IntegrationTests/FirebaseAdmin.IntegrationTests.csproj index 3edd66b0..d146599a 100644 --- a/FirebaseAdmin/FirebaseAdmin.IntegrationTests/FirebaseAdmin.IntegrationTests.csproj +++ b/FirebaseAdmin/FirebaseAdmin.IntegrationTests/FirebaseAdmin.IntegrationTests.csproj @@ -4,7 +4,6 @@ netcoreapp2.0 false true - true ../../stylecop_test.ruleset diff --git a/FirebaseAdmin/FirebaseAdmin.Snippets/FirebaseAdmin.Snippets.csproj b/FirebaseAdmin/FirebaseAdmin.Snippets/FirebaseAdmin.Snippets.csproj index 2a896f89..ee80a864 100644 --- a/FirebaseAdmin/FirebaseAdmin.Snippets/FirebaseAdmin.Snippets.csproj +++ b/FirebaseAdmin/FirebaseAdmin.Snippets/FirebaseAdmin.Snippets.csproj @@ -3,6 +3,8 @@ netcoreapp2.0 false + true + ../../stylecop_test.ruleset @@ -11,6 +13,9 @@ + + all + diff --git a/FirebaseAdmin/FirebaseAdmin.Snippets/FirebaseAppSnippets.cs b/FirebaseAdmin/FirebaseAdmin.Snippets/FirebaseAppSnippets.cs index 106daa1a..32ca9be5 100644 --- a/FirebaseAdmin/FirebaseAdmin.Snippets/FirebaseAppSnippets.cs +++ b/FirebaseAdmin/FirebaseAdmin.Snippets/FirebaseAppSnippets.cs @@ -21,9 +21,9 @@ namespace FirebaseAdmin.Snippets { - class FirebaseAppSnippets + internal class FirebaseAppSnippets { - static void InitSdkWithServiceAccount() + internal static void InitSdkWithServiceAccount() { // [START initialize_sdk_with_service_account] FirebaseApp.Create(new AppOptions() @@ -33,7 +33,7 @@ static void InitSdkWithServiceAccount() // [END initialize_sdk_with_service_account] } - static void InitSdkWithApplicationDefault() + internal static void InitSdkWithApplicationDefault() { // [START initialize_sdk_with_application_default] FirebaseApp.Create(new AppOptions() @@ -43,7 +43,7 @@ static void InitSdkWithApplicationDefault() // [END initialize_sdk_with_application_default] } - static void InitSdkWithRefreshToken() + internal static void InitSdkWithRefreshToken() { // [START initialize_sdk_with_refresh_token] FirebaseApp.Create(new AppOptions() @@ -53,14 +53,14 @@ static void InitSdkWithRefreshToken() // [END initialize_sdk_with_refresh_token] } - static void InitSdkWithDefaultConfig() + internal static void InitSdkWithDefaultConfig() { // [START initialize_sdk_with_default_config] FirebaseApp.Create(); // [END initialize_sdk_with_default_config] } - static void InitDefaultApp() + internal static void InitDefaultApp() { // [START access_services_default] // Initialize the default app @@ -78,7 +78,7 @@ static void InitDefaultApp() // [END access_services_default] } - static void InitCustomApp() + internal static void InitCustomApp() { var defaultOptions = new AppOptions() { @@ -107,7 +107,7 @@ static void InitCustomApp() // [END access_services_nondefault] } - static void InitWithServiceAccountId() + internal static void InitWithServiceAccountId() { // [START initialize_sdk_with_service_account_id] FirebaseApp.Create(new AppOptions() diff --git a/FirebaseAdmin/FirebaseAdmin.Snippets/FirebaseAuthSnippets.cs b/FirebaseAdmin/FirebaseAdmin.Snippets/FirebaseAuthSnippets.cs index bb7e094e..0afb71e2 100644 --- a/FirebaseAdmin/FirebaseAdmin.Snippets/FirebaseAuthSnippets.cs +++ b/FirebaseAdmin/FirebaseAdmin.Snippets/FirebaseAuthSnippets.cs @@ -19,9 +19,9 @@ namespace FirebaseAdmin.Snippets { - class FirebaseAuthSnippets + internal class FirebaseAuthSnippets { - static async Task CreateCustomTokenAsync() + internal static async Task CreateCustomTokenAsync() { // [START custom_token] var uid = "some-uid"; @@ -32,7 +32,7 @@ static async Task CreateCustomTokenAsync() Console.WriteLine("Created custom token: {0}", customToken); } - static async Task CreateCustomTokenWithClaimsAsync() + internal static async Task CreateCustomTokenWithClaimsAsync() { // [START custom_token_with_claims] var uid = "some-uid"; @@ -48,7 +48,7 @@ static async Task CreateCustomTokenWithClaimsAsync() Console.WriteLine("Created custom token: {0}", customToken); } - static async Task VeridyIdTokenAsync(string idToken) + internal static async Task VeridyIdTokenAsync(string idToken) { // [START verify_id_token] FirebaseToken decodedToken = await FirebaseAuth.DefaultInstance diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/FirebaseAdmin.Tests.csproj b/FirebaseAdmin/FirebaseAdmin.Tests/FirebaseAdmin.Tests.csproj index 903194ec..8641fa7b 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/FirebaseAdmin.Tests.csproj +++ b/FirebaseAdmin/FirebaseAdmin.Tests/FirebaseAdmin.Tests.csproj @@ -6,7 +6,6 @@ ../../FirebaseAdmin.snk true true - true ../../stylecop_test.ruleset diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs index a2226a04..11de31bf 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs @@ -277,6 +277,9 @@ public async Task VerifyIdTokenAsync( .ConfigureAwait(false); } + /// + /// Deletes this service instance. + /// void IFirebaseService.Delete() { lock (this.authLock) diff --git a/FirebaseAdmin/FirebaseAdmin/FirebaseAdmin.csproj b/FirebaseAdmin/FirebaseAdmin/FirebaseAdmin.csproj index 117c7603..5f6c5bbc 100644 --- a/FirebaseAdmin/FirebaseAdmin/FirebaseAdmin.csproj +++ b/FirebaseAdmin/FirebaseAdmin/FirebaseAdmin.csproj @@ -30,6 +30,7 @@ all + diff --git a/FirebaseAdmin/FirebaseAdmin/IFirebaseService.cs b/FirebaseAdmin/FirebaseAdmin/IFirebaseService.cs index d6075f4a..3407ef9f 100644 --- a/FirebaseAdmin/FirebaseAdmin/IFirebaseService.cs +++ b/FirebaseAdmin/FirebaseAdmin/IFirebaseService.cs @@ -20,6 +20,9 @@ namespace FirebaseAdmin /// internal interface IFirebaseService { + /// + /// Cleans up any state associated with this service making it unsuitable for further use. + /// void Delete(); } } diff --git a/stylecop.json b/stylecop.json new file mode 100644 index 00000000..b38dbb7c --- /dev/null +++ b/stylecop.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", + "settings": { + "documentationRules": { + "documentInternalElements": false + } + } +} \ No newline at end of file diff --git a/stylecop.ruleset b/stylecop.ruleset index fe083603..98c8be6f 100644 --- a/stylecop.ruleset +++ b/stylecop.ruleset @@ -6,7 +6,6 @@ - \ No newline at end of file diff --git a/stylecop_test.ruleset b/stylecop_test.ruleset index eb44502a..c088d3c0 100644 --- a/stylecop_test.ruleset +++ b/stylecop_test.ruleset @@ -7,11 +7,14 @@ + + + \ No newline at end of file From ad58b40bdb37a124d2cb1b96d4e93903529d9ca1 Mon Sep 17 00:00:00 2001 From: hiranya911 Date: Mon, 21 Jan 2019 22:15:04 -0800 Subject: [PATCH 11/13] Added missing newlines at eof --- FirebaseAdmin/FirebaseAdmin/Auth/FixedAccountIAMSigner.cs | 2 +- FirebaseAdmin/FirebaseAdmin/Auth/IAMSigner.cs | 2 +- stylecop.json | 2 +- stylecop.ruleset | 2 +- stylecop_test.ruleset | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FixedAccountIAMSigner.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FixedAccountIAMSigner.cs index 92123bd2..8398d9fb 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/FixedAccountIAMSigner.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FixedAccountIAMSigner.cs @@ -42,4 +42,4 @@ public override Task GetKeyIdAsync( return Task.FromResult(this.keyId); } } -} \ No newline at end of file +} diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/IAMSigner.cs b/FirebaseAdmin/FirebaseAdmin/Auth/IAMSigner.cs index 9051c343..f7d810bd 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/IAMSigner.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/IAMSigner.cs @@ -173,4 +173,4 @@ private class SignBlobErrorDetail public string Message { get; set; } } } -} \ No newline at end of file +} diff --git a/stylecop.json b/stylecop.json index b38dbb7c..56f05687 100644 --- a/stylecop.json +++ b/stylecop.json @@ -5,4 +5,4 @@ "documentInternalElements": false } } -} \ No newline at end of file +} diff --git a/stylecop.ruleset b/stylecop.ruleset index 98c8be6f..8a4c10a4 100644 --- a/stylecop.ruleset +++ b/stylecop.ruleset @@ -8,4 +8,4 @@ - \ No newline at end of file + diff --git a/stylecop_test.ruleset b/stylecop_test.ruleset index c088d3c0..aaef9717 100644 --- a/stylecop_test.ruleset +++ b/stylecop_test.ruleset @@ -17,4 +17,4 @@ - \ No newline at end of file + From e6bb4d2a6bc93d20a36f79ee3042be3a6f67b2b4 Mon Sep 17 00:00:00 2001 From: hiranya911 Date: Wed, 23 Jan 2019 15:08:46 -0800 Subject: [PATCH 12/13] Adding required constant --- FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenVerifier.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenVerifier.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenVerifier.cs index fc9fc1b6..172fa03e 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenVerifier.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseTokenVerifier.cs @@ -38,6 +38,9 @@ internal sealed class FirebaseTokenVerifier private const string FirebaseAudience = "https://identitytoolkit.googleapis.com/" + "google.identity.identitytoolkit.v1.IdentityToolkit"; + // See http://oid-info.com/get/2.16.840.1.101.3.4.2.1 + private const string Sha256Oid = "2.16.840.1.101.3.4.2.1"; + private static readonly IReadOnlyList StandardClaims = ImmutableList.Create("iss", "aud", "exp", "iat", "sub", "uid"); From b1221bf0f842b4444de2252a080bab07b5c8e49d Mon Sep 17 00:00:00 2001 From: hiranya911 Date: Thu, 7 Feb 2019 16:34:30 -0800 Subject: [PATCH 13/13] Fixing a typo --- FirebaseAdmin/FirebaseAdmin/Auth/FirebaseToken.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseToken.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseToken.cs index 9cd4cc23..6145e805 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseToken.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseToken.cs @@ -68,7 +68,7 @@ internal FirebaseToken(FirebaseTokenArgs args) public string Uid { get; private set; } /// - /// Gets Aall other claims present in the JWT as a readonly dictionary. This can be used to + /// Gets all other claims present in the JWT as a readonly dictionary. This can be used to /// access custom claims of the token. /// public IReadOnlyDictionary Claims { get; private set; }