예제 #1
0
        public static string ExtractToken(string authorizationHeader, out string tokenType)
        {
            if (string.IsNullOrEmpty(authorizationHeader))
            {
                tokenType = null;
                return(null);
            }

            var parts = authorizationHeader.Split(' ');

            if (parts.Length > 2)
            {
                throw ErtisAuthException.InvalidToken();
            }

            if (parts.Length == 2)
            {
                var supportedTokenTypes = Enum.GetValues(typeof(SupportedTokenTypes)).Cast <SupportedTokenTypes>().Select(x => x.ToString());
                if (!supportedTokenTypes.Contains(parts[0]))
                {
                    throw ErtisAuthException.UnsupportedTokenType();
                }

                tokenType = parts[0];
                return(parts[1]);
            }

            tokenType = null;
            return(parts[0]);
        }
예제 #2
0
        public async Task SetPasswordAsync(Utilizer utilizer, string membershipId, string resetToken, string usernameOrEmailAddress, string password)
        {
            if (string.IsNullOrEmpty(usernameOrEmailAddress))
            {
                throw ErtisAuthException.ValidationError(new []
                {
                    "Username or email required!"
                });
            }

            var membership = await this.membershipService.GetAsync(membershipId);

            if (membership == null)
            {
                throw ErtisAuthException.MembershipNotFound(membershipId);
            }

            var user = await this.GetUserWithPasswordAsync(usernameOrEmailAddress, usernameOrEmailAddress, membershipId);

            if (user == null)
            {
                throw ErtisAuthException.UserNotFound(usernameOrEmailAddress, "username or email_address");
            }

            if (utilizer.Role == Rbac.ReservedRoles.Administrator || utilizer.Id == user.Id)
            {
                if (this.jwtService.TryDecodeToken(resetToken, out var securityToken))
                {
                    var expireTime = securityToken.ValidTo.ToLocalTime();
                    if (DateTime.Now > expireTime)
                    {
                        // Token was expired!
                        throw ErtisAuthException.TokenWasExpired();
                    }

                    await this.ChangePasswordAsync(utilizer, membershipId, user.Id, password);
                }
                else
                {
                    // Reset token could not decoded!
                    throw ErtisAuthException.InvalidToken();
                }
            }
            else
            {
                throw ErtisAuthException.AccessDenied("Unauthorized access");
            }
        }
예제 #3
0
        private async Task <Application> GetTokenOwnerApplicationAsync(string basicToken)
        {
            var parts = basicToken.Split(':');

            if (parts.Length != 2)
            {
                throw ErtisAuthException.InvalidToken();
            }

            var applicationId = parts[0];
            var application   = await this.applicationService.GetByIdAsync(applicationId);

            if (application == null)
            {
                throw ErtisAuthException.ApplicationNotFound(applicationId);
            }

            return(application);
        }
예제 #4
0
        public async Task <BasicTokenValidationResult> VerifyBasicTokenAsync(string basicToken, bool fireEvent = true)
        {
            if (string.IsNullOrEmpty(basicToken))
            {
                throw ErtisAuthException.InvalidToken();
            }

            var parts = basicToken.Split(':');

            if (parts.Length != 2)
            {
                throw ErtisAuthException.InvalidToken();
            }

            var applicationId = parts[0];
            var application   = await this.applicationService.GetByIdAsync(applicationId);

            if (application == null)
            {
                throw ErtisAuthException.ApplicationNotFound(applicationId);
            }

            var membership = await this.membershipService.GetAsync(application.MembershipId);

            if (membership == null)
            {
                throw ErtisAuthException.MembershipNotFound(application.MembershipId);
            }

            var secret = parts[1];

            if (membership.SecretKey != secret)
            {
                throw ErtisAuthException.ApplicationSecretMismatch();
            }

            if (fireEvent)
            {
                await this.eventService.FireEventAsync(this, new ErtisAuthEvent(ErtisAuthEventType.TokenVerified, application, new { basicToken }));
            }

            return(new BasicTokenValidationResult(true, basicToken, application));
        }
예제 #5
0
 private async Task <User> GetTokenOwnerAsync(JwtSecurityToken securityToken)
 {
     if (this.TryExtractClaimValue(securityToken, JwtRegisteredClaimNames.Prn, out var membershipId) && !string.IsNullOrEmpty(membershipId))
     {
         var userId = securityToken.Subject;
         if (!string.IsNullOrEmpty(userId))
         {
             return(await this.userService.GetAsync(membershipId, userId));
         }
         else
         {
             // UserId could not found in token claims!
             throw ErtisAuthException.InvalidToken();
         }
     }
     else
     {
         // MembershipId could not found in token claims!
         throw ErtisAuthException.InvalidToken();
     }
 }
예제 #6
0
        public async Task <bool> RevokeTokenAsync(string token, bool fireEvent = true)
        {
            var validationResult = await this.VerifyBearerTokenAsync(token, false);

            if (!validationResult.IsValidated)
            {
                throw ErtisAuthException.InvalidToken();
            }

            await this.revokedTokensRepository.InsertAsync(new RevokedTokenDto
            {
                Token     = token,
                RevokedAt = DateTime.Now,
                UserId    = validationResult.User.Id
            });

            var membership = await this.membershipService.GetAsync(validationResult.User.MembershipId);

            if (membership == null)
            {
                throw ErtisAuthException.MembershipNotFound(validationResult.User.MembershipId);
            }

            if (this.jwtService.TryDecodeToken(token, out var securityToken))
            {
                if (!this.IsRefreshToken(securityToken))
                {
                    var refreshToken = this.StimulateRefreshToken(token, validationResult.User, membership);
                    if (!string.IsNullOrEmpty(refreshToken))
                    {
                        await this.RevokeRefreshTokenAsync(refreshToken);
                    }
                }
            }

            await this.eventService.FireEventAsync(this, new ErtisAuthEvent(ErtisAuthEventType.TokenRevoked, validationResult.User, new { token }));

            return(true);
        }
예제 #7
0
        private async Task <Utilizer> CheckAuthorizationAsync(HttpContext httpContext)
        {
            var token = httpContext.Request.GetTokenFromHeader(out var tokenType);

            if (string.IsNullOrEmpty(token))
            {
                throw ErtisAuthException.AuthorizationHeaderMissing();
            }

            if (string.IsNullOrEmpty(tokenType))
            {
                throw ErtisAuthException.UnsupportedTokenType();
            }

            switch (tokenType)
            {
            case "Bearer":
            {
                var verifyTokenResult = await this.tokenService.VerifyBearerTokenAsync(token, false);

                if (!verifyTokenResult.IsValidated)
                {
                    throw ErtisAuthException.InvalidToken();
                }

                var user = verifyTokenResult.User;
                if (!string.IsNullOrEmpty(user.Role))
                {
                    var role = await this.roleService.GetByNameAsync(user.Role, user.MembershipId);

                    if (role != null)
                    {
                        this.VerifyRolePermissions(role, user.Id, httpContext);
                    }
                }

                return(user);
            }

            case "Basic":
            {
                var validationResult = await this.tokenService.VerifyBasicTokenAsync(token);

                if (!validationResult.IsValidated)
                {
                    throw ErtisAuthException.InvalidToken();
                }

                var application = validationResult.Application;
                if (!string.IsNullOrEmpty(application.Role))
                {
                    var role = await this.roleService.GetByNameAsync(application.Role, application.MembershipId);

                    if (role != null)
                    {
                        this.VerifyRolePermissions(role, application.Id, httpContext);
                    }
                }

                return(application);
            }

            default:
                throw ErtisAuthException.UnsupportedTokenType();
            }
        }
예제 #8
0
 public static UnauthorizedObjectResult InvalidToken(this ControllerBase controller)
 {
     return(controller.Unauthorized(ErtisAuthException.InvalidToken().Error));
 }
예제 #9
0
        public async Task <BearerToken> RefreshTokenAsync(string refreshToken, bool revokeBefore = true, bool fireEvent = true)
        {
            var revokedToken = await this.revokedTokensRepository.FindOneAsync(x => x.Token == refreshToken);

            if (revokedToken != null)
            {
                throw ErtisAuthException.RefreshTokenWasRevoked();
            }

            if (this.jwtService.TryDecodeToken(refreshToken, out var securityToken))
            {
                if (this.IsRefreshToken(securityToken))
                {
                    var expireTime = securityToken.ValidTo.ToLocalTime();
                    if (DateTime.Now <= expireTime)
                    {
                        if (this.TryExtractClaimValue(securityToken, JwtRegisteredClaimNames.Prn, out var membershipId) && !string.IsNullOrEmpty(membershipId))
                        {
                            var membership = await this.membershipService.GetAsync(membershipId);

                            if (membership != null)
                            {
                                var userId = securityToken.Subject;
                                if (!string.IsNullOrEmpty(userId))
                                {
                                    var user = await this.userService.GetAsync(membershipId, userId);

                                    if (user != null)
                                    {
                                        var token = this.GenerateBearerToken(user, membership);

                                        if (revokeBefore)
                                        {
                                            await this.RevokeTokenAsync(refreshToken);
                                        }

                                        if (fireEvent)
                                        {
                                            await this.eventService.FireEventAsync(this, new ErtisAuthEvent(ErtisAuthEventType.TokenRefreshed, user, token, new { refreshToken }));
                                        }

                                        return(token);
                                    }
                                    else
                                    {
                                        // User not found!
                                        throw ErtisAuthException.UserNotFound(userId, "_id");
                                    }
                                }
                                else
                                {
                                    // UserId could not found in token claims!
                                    throw ErtisAuthException.InvalidToken();
                                }
                            }
                            else
                            {
                                // Membership not found!
                                throw ErtisAuthException.MembershipNotFound(membershipId);
                            }
                        }
                        else
                        {
                            // MembershipId could not found in token claims!
                            throw ErtisAuthException.InvalidToken();
                        }
                    }
                    else
                    {
                        // Token was expired!
                        throw ErtisAuthException.RefreshTokenWasExpired();
                    }
                }
                else
                {
                    // This is not a refresh token!
                    throw ErtisAuthException.TokenIsNotRefreshable();
                }
            }
            else
            {
                // Token could not decoded!
                throw ErtisAuthException.InvalidToken();
            }
        }
예제 #10
0
        public async Task <BearerTokenValidationResult> VerifyBearerTokenAsync(string token, bool fireEvent = true)
        {
            var revokedToken = await this.revokedTokensRepository.FindOneAsync(x => x.Token == token);

            if (revokedToken != null)
            {
                throw ErtisAuthException.TokenWasRevoked();
            }

            if (this.jwtService.TryDecodeToken(token, out var securityToken))
            {
                var expireTime = securityToken.ValidTo.ToLocalTime();
                if (DateTime.Now <= expireTime)
                {
                    var user = await this.GetTokenOwnerAsync(securityToken);

                    if (user != null)
                    {
                        if (this.TryExtractClaimValue(securityToken, JwtRegisteredClaimNames.Prn, out var membershipId) && !string.IsNullOrEmpty(membershipId))
                        {
                            var membership = await this.membershipService.GetAsync(membershipId);

                            if (membership != null)
                            {
                                var encoding          = membership.GetEncoding();
                                var secretSecurityKey = new SymmetricSecurityKey(encoding.GetBytes(membership.SecretKey));
                                var tokenClaims       = new TokenClaims(null, user, membership);
                                if (!this.jwtService.ValidateToken(token, tokenClaims, secretSecurityKey, out _))
                                {
                                    // Token signature not verified!
                                    throw ErtisAuthException.InvalidToken("Token signature could not verified!");
                                }
                            }
                            else
                            {
                                // Membership not found!
                                throw ErtisAuthException.MembershipNotFound(membershipId);
                            }
                        }
                        else
                        {
                            // MembershipId could not found in token claims!
                            throw ErtisAuthException.InvalidToken();
                        }

                        if (fireEvent)
                        {
                            await this.eventService.FireEventAsync(this, new ErtisAuthEvent(ErtisAuthEventType.TokenVerified, user, new { token }));
                        }

                        return(new BearerTokenValidationResult(true, token, user, expireTime - DateTime.Now, this.IsRefreshToken(securityToken)));
                    }
                    else
                    {
                        // User not found!
                        var userId = securityToken.Subject;
                        throw ErtisAuthException.UserNotFound(userId, "_id");
                    }
                }
                else
                {
                    // Token was expired!
                    throw ErtisAuthException.TokenWasExpired();
                }
            }
            else
            {
                // Token could not decoded!
                throw ErtisAuthException.InvalidToken();
            }
        }
예제 #11
0
        private async Task <Utilizer> CheckAuthorizationAsync()
        {
            var token = this.Context.Request.GetTokenFromHeader(out var tokenType);

            if (string.IsNullOrEmpty(token))
            {
                throw ErtisAuthException.AuthorizationHeaderMissing();
            }

            if (string.IsNullOrEmpty(tokenType))
            {
                throw ErtisAuthException.UnsupportedTokenType();
            }

            TokenTypeExtensions.TryParseTokenType(tokenType, out var _tokenType);
            switch (_tokenType)
            {
            case SupportedTokenTypes.None:
                throw ErtisAuthException.UnsupportedTokenType();

            case SupportedTokenTypes.Basic:
                var validationResult = await this.tokenService.VerifyBasicTokenAsync(token, false);

                if (!validationResult.IsValidated)
                {
                    throw ErtisAuthException.InvalidToken();
                }

                var      application         = validationResult.Application;
                Utilizer applicationUtilizer = application;
                if (!string.IsNullOrEmpty(application.Role))
                {
                    var role = await this.roleService.GetByNameAsync(application.Role, application.MembershipId);

                    if (role != null)
                    {
                        var rbac = this.Context.GetRbacDefinition(application.Id);
                        if (!this.accessControlService.HasPermission(role, rbac, applicationUtilizer))
                        {
                            throw ErtisAuthException.AccessDenied("Your authorization role is unauthorized for this action");
                        }
                    }
                }

                applicationUtilizer.Token     = token;
                applicationUtilizer.TokenType = _tokenType;
                return(applicationUtilizer);

            case SupportedTokenTypes.Bearer:
                var verifyTokenResult = await this.tokenService.VerifyBearerTokenAsync(token, false);

                if (!verifyTokenResult.IsValidated)
                {
                    throw ErtisAuthException.InvalidToken();
                }

                var      user         = verifyTokenResult.User;
                Utilizer userUtilizer = user;
                if (!string.IsNullOrEmpty(user.Role))
                {
                    var role = await this.roleService.GetByNameAsync(user.Role, user.MembershipId);

                    if (role != null)
                    {
                        var rbac = this.Context.GetRbacDefinition(user.Id);
                        if (!this.accessControlService.HasPermission(role, rbac, userUtilizer))
                        {
                            throw ErtisAuthException.AccessDenied("Your authorization role is unauthorized for this action");
                        }
                    }
                }

                userUtilizer.Token     = token;
                userUtilizer.TokenType = _tokenType;
                return(userUtilizer);

            default:
                throw ErtisAuthException.UnsupportedTokenType();
            }
        }
예제 #12
0
        public async ValueTask <bool> RevokeTokenAsync(string token, bool logoutFromAllDevices = false, bool fireEvent = true)
        {
            User user;

            try
            {
                var validationResult = await this.VerifyBearerTokenAsync(token, false);

                user = validationResult.User;
                if (!validationResult.IsValidated)
                {
                    throw ErtisAuthException.InvalidToken();
                }
            }
            catch (ErtisAuthException ex)
            {
                if (ex.ErrorCode == ErtisAuthException.TokenWasRevoked().ErrorCode)
                {
                    Console.WriteLine("This token was revoked already");
                }

                return(false);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                return(false);
            }

            var activeTokenDtos = await this.GetActiveTokensByUser(user.Id, user.MembershipId);

            var filteredActiveTokenDtos = logoutFromAllDevices ? activeTokenDtos : new[] { activeTokenDtos.FirstOrDefault(x => x.AccessToken == token) };
            var activeTokens            = filteredActiveTokenDtos.Where(x => x != null).ToArray();

            if (activeTokens.Any())
            {
                foreach (var activeTokenDto in activeTokens)
                {
                    var isRefreshToken = false;
                    if (this.jwtService.TryDecodeToken(activeTokenDto.AccessToken, out var securityToken))
                    {
                        isRefreshToken = this.IsRefreshToken(securityToken);
                    }

                    await this.revokedTokensRepository.InsertAsync(new RevokedTokenDto
                    {
                        Token        = activeTokenDto.AccessToken,
                        RevokedAt    = DateTime.Now,
                        UserId       = user.Id,
                        UserName     = user.Username,
                        EmailAddress = user.EmailAddress,
                        FirstName    = user.FirstName,
                        LastName     = user.LastName,
                        MembershipId = user.MembershipId,
                        TokenType    = isRefreshToken ? "refresh_token" : "bearer_token"
                    });

                    var membership = await this.membershipService.GetAsync(user.MembershipId);

                    if (membership == null)
                    {
                        throw ErtisAuthException.MembershipNotFound(user.MembershipId);
                    }

                    if (!isRefreshToken)
                    {
                        var refreshToken = this.StimulateRefreshToken(activeTokenDto.AccessToken, user, membership);
                        if (!string.IsNullOrEmpty(refreshToken))
                        {
                            await this.RevokeRefreshTokenAsync(refreshToken);
                        }
                    }

                    await this.eventService.FireEventAsync(this, new ErtisAuthEvent(ErtisAuthEventType.TokenRevoked, user, new { activeTokenDto.AccessToken }) { MembershipId = membership.Id });
                }

                await this.activeTokensRepository.BulkDeleteAsync(activeTokens);
            }

            return(true);
        }
예제 #13
0
        public async ValueTask <BasicTokenValidationResult> VerifyBasicTokenAsync(string basicToken, bool fireEvent = true)
        {
            if (string.IsNullOrEmpty(basicToken))
            {
                throw ErtisAuthException.InvalidToken();
            }

            var parts = basicToken.Split(':');

            if (parts.Length != 2)
            {
                throw ErtisAuthException.InvalidToken();
            }

            var applicationId = parts[0];
            var secret        = parts[1];

            var application = await this.applicationService.GetByIdAsync(applicationId);

            if (application == null)
            {
                throw ErtisAuthException.ApplicationNotFound(applicationId);
            }

            var membership = await this.membershipService.GetAsync(application.MembershipId);

            if (membership == null)
            {
                if (this.applicationService.IsSystemReservedApplication(application))
                {
                    membership = await this.membershipService.GetBySecretKeyAsync(secret);

                    var onTheFlyApplication = new Application
                    {
                        Id           = application.Id,
                        Name         = application.Name,
                        Role         = application.Role,
                        Permissions  = application.Permissions,
                        Forbidden    = application.Forbidden,
                        Sys          = application.Sys,
                        MembershipId = membership.Id
                    };

                    application = onTheFlyApplication;
                }

                if (membership == null)
                {
                    throw ErtisAuthException.MembershipNotFound(application.MembershipId);
                }
            }

            if (membership.SecretKey != secret)
            {
                throw ErtisAuthException.ApplicationSecretMismatch();
            }

            if (fireEvent)
            {
                await this.eventService.FireEventAsync(this, new ErtisAuthEvent(ErtisAuthEventType.TokenVerified, application, new { basicToken }) { MembershipId = membership.Id });
            }

            return(new BasicTokenValidationResult(true, basicToken, application));
        }