예제 #1
0
        public async Task <ServiceResponse <JwtTokens> > Login()
        {
            if (!HttpListener.IsSupported)
            {
                throw new HttpListenerNotSupportedException();
            }

            var listener = new HttpListener();

            listener.Prefixes.Add($"{this.configuration.CallbackUrl}/");
            listener.Start();

            HttpListenerContext requestContext = await this.HandleAuthCallback(listener);

            HttpListenerRequest httpRequest = requestContext.Request;

            string    authCode = httpRequest.QueryString["code"];
            JwtTokens tokens   = await this.RequestJwtTokens(authCode);

            if (tokens == null)
            {
                await this.RespondWithFailedLogin(requestContext);

                listener.Stop();
                return(null);
            }

            await this.RespondWithSuccessfulLogin(requestContext);

            listener.Stop();

            return(new ServiceResponse <JwtTokens>(tokens));
        }
예제 #2
0
        public async Task AuthorizeUser_ReturnsTokens()
        {
            // Arrange
            var       tokenFactory = new TestTokenFactory();
            string    id_token     = tokenFactory.GetIdToken(true);
            string    access_token = tokenFactory.GetAccessToken(false);
            JwtTokens tokens       = new JwtTokens {
                AccessToken = access_token, IdToken = id_token
            };

            Mock <ITokenRepository> repositoryMock = new Mock <ITokenRepository>();
            Mock <ILogger <OAuthAuthorizationService> > loggerMock = new Mock <ILogger <OAuthAuthorizationService> >();
            Mock <ILoginService> loginMock = new Mock <ILoginService>();

            loginMock
            .Setup(mock => mock.Login())
            .Returns(Task.FromResult(new ServiceResponse <JwtTokens>(tokens)));

            IAccountService accountService = new OAuthAuthorizationService(repositoryMock.Object, loginMock.Object, loggerMock.Object);

            // Act
            ServiceResponse <LoginResponse> authResponse = await accountService.AuthorizeUser();

            // Assert
            Assert.IsNotNull(authResponse.Data.AccessToken.UserId);
            Assert.AreNotEqual(0, authResponse.Data.AccessToken.Scopes.Length);
            Assert.AreNotEqual(0, authResponse.Data.AccessToken.ExpiresAt);

            // Ensure we cleaned up previous auth sessions, attempted to perform a login and then saved the new auth tokens.
            repositoryMock.Verify(repo => repo.DeleteToken(), Times.Once);
            repositoryMock.Verify(repo => repo.SaveToken(It.IsAny <JwtTokens>()), Times.Once);
            loginMock.Verify(repo => repo.Login(), Times.Once);
        }
예제 #3
0
        public async Task <ServiceResponse <LoginResponse> > AuthorizeUser()
        {
            await this.DeauthorizeUser();

            ServiceResponse <JwtTokens> loginResponse = await this.loginService.Login();

            if (loginResponse?.Data == null)
            {
                ResponseError loginError = new ResponseError(SDKErrors.LoginFailed.Code, SDKErrors.LoginFailed.Message);
                return(new ServiceResponse <LoginResponse>(loginError));
            }

            JwtTokens jwtTokens = loginResponse.Data;

            try
            {
                await this.tokenRepository.SaveToken(loginResponse.Data);

                return(new ServiceResponse <LoginResponse>(new LoginResponse(jwtTokens)));
            }
            catch (Exception)
            {
                var saveTokenError = new ResponseError(SDKErrors.SaveTokenFailed.Code, SDKErrors.SaveTokenFailed.Message);
                return(new ServiceResponse <LoginResponse>(saveTokenError));
            }
        }
예제 #4
0
        public Task <JwtTokens> GetToken()
        {
            // Get a reference to the database that stores the tokens.
            ILiteDatabase database        = this.databaseFactory.GetDatabase(DatabaseName);
            JwtTokens     protectedTokens = null;

            using (database)
            {
                ILiteCollection <JwtTokens> tokenCollection = database.GetCollection <JwtTokens>(TokenCollection);

                // Find the access token record. There should only ever be 1 record in the database at a time.
                protectedTokens = tokenCollection.FindOne(token => !string.IsNullOrEmpty(token.AccessToken));
                if (protectedTokens == null)
                {
                    return(Task.FromResult <JwtTokens>(null));
                }
            }

            // Unprotect the tokens and return them.
            try
            {
                JwtTokens unprotectedTokens = this.UnprotectTokens(protectedTokens);
                return(Task.FromResult(unprotectedTokens));
            }
            catch (CryptographicException)
            {
                this.logger.LogError("Failed to unprotect tokens. Potentially tampered with.");
                return(Task.FromResult <JwtTokens>(null));
            }
        }
예제 #5
0
        public async Task <ServiceResponse <JwtTokens> > GetTokens()
        {
            this.logger.LogInformation("Fetching previously retrieved tokens.");
            JwtTokens token = await this.tokenRepository.GetToken();

            if (token == null)
            {
                this.logger.LogError("User is not currently logged into their account.");
                var getTokenFailed = new ResponseError(SDKErrors.LoadTokensFailed.Code, SDKErrors.LoadTokensFailed.Message);
                return(new ServiceResponse <JwtTokens>(getTokenFailed));
            }

            return(new ServiceResponse <JwtTokens>(token));
        }
예제 #6
0
        public void JsonDeserialization_AssignsValues()
        {
            // Arrange
            var    tokenFactory    = new TestTokenFactory();
            string idTokenJson     = tokenFactory.GetIdToken(false);
            string accessTokenJson = tokenFactory.GetAccessToken(false);
            string jwtTokenJson    = JsonSerializer.Serialize(new { id_token = idTokenJson, access_token = accessTokenJson });

            // Act
            JwtTokens jwtTokens = Newtonsoft.Json.JsonConvert.DeserializeObject <JwtTokens>(jwtTokenJson);

            // Assert
            Assert.AreEqual(idTokenJson, jwtTokens.IdToken, "Expected the id_token value to have been assigned");
            Assert.AreEqual(accessTokenJson, jwtTokens.AccessToken, "Expected the access_token value to have been assigned");
        }
예제 #7
0
        public void AccessToken_HasExpiredToken()
        {
            // Arrange
            var    tokenFactory    = new TestTokenFactory();
            string idTokenJson     = tokenFactory.GetIdToken(false);
            string accessTokenJson = tokenFactory.GetAccessToken(true);
            string jwtTokenJson    = JsonSerializer.Serialize(new { id_token = idTokenJson, access_token = accessTokenJson });

            JwtTokens jwtTokens = Newtonsoft.Json.JsonConvert.DeserializeObject <JwtTokens>(jwtTokenJson);

            // Act
            bool isExpired = jwtTokens.IsAccessTokenExpired();

            // Assert
            Assert.IsTrue(isExpired);
        }
예제 #8
0
        public void IdToken_GetTokenReturnsValue()
        {
            // Arrange
            var    tokenFactory    = new TestTokenFactory();
            string idTokenJson     = tokenFactory.GetIdToken(true);
            string accessTokenJson = tokenFactory.GetAccessToken(false);
            string jwtTokenJson    = JsonSerializer.Serialize(new { id_token = idTokenJson, access_token = accessTokenJson });

            JwtTokens jwtTokens = Newtonsoft.Json.JsonConvert.DeserializeObject <JwtTokens>(jwtTokenJson);

            // Act
            IdToken idToken = jwtTokens.GetIdToken();

            // Assert
            Assert.IsNotNull(idToken.UserId);
            Assert.IsNotNull(idToken.Username);
            Assert.AreNotEqual(0, idToken.ExpiresAt);
        }
예제 #9
0
        public Task SaveToken(JwtTokens jwtToken)
        {
            if (jwtToken is null || string.IsNullOrEmpty(jwtToken.AccessToken) || string.IsNullOrEmpty(jwtToken.IdToken) || string.IsNullOrEmpty(jwtToken.RefreshToken))
            {
                throw new ArgumentNullException(nameof(jwtToken));
            }

            JwtTokens     protectedTokens = this.ProtectTokens(jwtToken);
            ILiteDatabase database        = this.databaseFactory.GetDatabase(DatabaseName);

            using (database)
            {
                ILiteCollection <JwtTokens> tokenCollection = database.GetCollection <JwtTokens>(TokenCollection);
                tokenCollection.Insert(protectedTokens);
            }

            return(Task.CompletedTask);
        }
예제 #10
0
        private JwtTokens UnprotectTokens(JwtTokens protectedTokens)
        {
            // Create a Protector and start unprotecting the tokens
            IDataProtector authProtector = this.protectionProvider.CreateProtector(TokenProtector);

            IDataProtector accessTokenProtector = authProtector.CreateProtector(AccessTokenProtector);
            string         accessToken          = accessTokenProtector.Unprotect(protectedTokens.AccessToken);

            IDataProtector idTokenProtector = authProtector.CreateProtector(IdTokenProtector);
            string         idToken          = idTokenProtector.Unprotect(protectedTokens.IdToken);

            IDataProtector refreshTokenProtector = authProtector.CreateProtector(RefreshTokenProtector);
            string         refreshToken          = refreshTokenProtector.Unprotect(protectedTokens.RefreshToken);

            // Return the unprotected tokens for use.
            return(new JwtTokens
            {
                AccessToken = accessToken,
                IdToken = idToken,
                RefreshToken = refreshToken,
            });
        }
예제 #11
0
        public async Task AuthorizeUser_ReturnsErrorWhenSavingFails()
        {
            // Arrange
            var       tokenFactory = new TestTokenFactory();
            string    id_token     = tokenFactory.GetIdToken(true);
            string    access_token = tokenFactory.GetAccessToken(false);
            JwtTokens tokens       = new JwtTokens {
                AccessToken = access_token, IdToken = id_token
            };

            Mock <ILogger <OAuthAuthorizationService> > loggerMock = new Mock <ILogger <OAuthAuthorizationService> >();

            Mock <ITokenRepository> repositoryMock = new Mock <ITokenRepository>();

            repositoryMock
            .Setup(repo => repo.SaveToken(It.IsAny <JwtTokens>()))
            .Throws <Exception>();

            Mock <ILoginService> loginMock = new Mock <ILoginService>();

            loginMock
            .Setup(mock => mock.Login())
            .Returns(Task.FromResult(new ServiceResponse <JwtTokens>(tokens)));

            IAccountService accountService = new OAuthAuthorizationService(repositoryMock.Object, loginMock.Object, loggerMock.Object);

            // Act
            ServiceResponse <LoginResponse> authResponse = await accountService.AuthorizeUser();

            // Assert
            Assert.IsNull(authResponse.Data);
            Assert.AreEqual(1, authResponse.Errors.Length);
            Assert.AreEqual(SDKErrors.SaveTokenFailed.Code, authResponse.Errors[0].Code);
            Assert.AreEqual(SDKErrors.SaveTokenFailed.Message, authResponse.Errors[0].Message);
            repositoryMock.Verify(repo => repo.DeleteToken(), Times.Once);
            repositoryMock.Verify(repo => repo.SaveToken(It.IsAny <JwtTokens>()), Times.Once);
            loginMock.Verify(repo => repo.Login(), Times.Once);
        }
예제 #12
0
        private JwtTokens ProtectTokens(JwtTokens jwtTokens)
        {
            IDataProtector authProtector = this.protectionProvider.CreateProtector(TokenProtector);

            // Protect Access Token with a unique protector
            IDataProtector accessTokenProtector = authProtector.CreateProtector(AccessTokenProtector);
            string         encryptedAccessToken = accessTokenProtector.Protect(jwtTokens.AccessToken);

            // Protect Id Token with a unique protector
            IDataProtector idTokenProtector = authProtector.CreateProtector(IdTokenProtector);
            string         encryptedIdToken = idTokenProtector.Protect(jwtTokens.IdToken);

            // Protect Refresh Token with a unique protector
            IDataProtector refreshTokenProtector = authProtector.CreateProtector(RefreshTokenProtector);
            string         encryptedRefreshToken = refreshTokenProtector.Protect(jwtTokens.RefreshToken);

            return(new JwtTokens
            {
                AccessToken = encryptedAccessToken,
                IdToken = encryptedIdToken,
                RefreshToken = encryptedRefreshToken,
            });
        }