internal RegistrationManager(
            IRegistrationContext registrationContext, 
            IModuleManager moduleManager,
            IPublicRegistrationService publicRegistrationService, 
            ISdkInformation sdkInformation,
            IEnvironmentInformation environmentInformation, 
            IServiceContext serviceContext,
            ISecureRegistrationService secureRegistrationService, 
            IConfigurationManager configurationManager,
            IEventBus eventBus, 
            IRefreshToken tokenRefresher, 
            ILogger logger,
			IJsonSerialiser serialiser)
        {
            _registrationContext = registrationContext;
            _moduleManager = moduleManager;
            _publicRegistrationService = publicRegistrationService;
            _sdkInformation = sdkInformation;
            _environmentInformation = environmentInformation;
            _serviceContext = serviceContext;
            _secureRegistrationService = secureRegistrationService;
            _configurationManager = configurationManager;
            _eventBus = eventBus;
            _tokenRefresher = tokenRefresher;
            _logger = logger;
			_serialiser = serialiser;
        }
        /// <summary>Tests if this IRefreshToken is considered equal to another.</summary>
        /// <param name="other">The i refresh token to compare to this object.</param>
        /// <returns>true if the objects are considered equal, false if they are not.</returns>
        public bool Equals(IRefreshToken other)
        {
            if (this.ClientId == other.ClientId && this.RedirectUri == other.RedirectUri && this.Subject == other.Subject && this.ValidTo == other.ValidTo)
            {
                return true;
            }

            return false;
        }
        /// <summary>Inserts the specified refresh token. Called when creating a refresh token.</summary>
        /// <param name="refreshToken">The refresh token.</param>
        /// <returns>The inserted refresh token. <c>null</c> if the insertion was unsuccessful.</returns>
        public async Task<IRefreshToken> InsertRefreshToken(IRefreshToken refreshToken)
        {
            var token = (SqlRefreshToken)refreshToken;

            using (var connection = this.OpenConnection())
            {
                var id =
                    await
                    connection.QueryAsync<long>(
                        "INSERT INTO RefreshTokens (ClientId, RedirectUri, Subject, Scope, Token, ValidTo, Created) VALUES (@ClientId, @RedirectUri, @Subject, @Scope, @Token, @ValidTo, @Created); SELECT CAST(SCOPE_IDENTITY() as bigint);",
                        new
                        {
                            refreshToken.ClientId,
                            refreshToken.RedirectUri,
                            refreshToken.Subject,
                            Scope = string.Join(" ", token.Scope),
                            refreshToken.Token,
                            refreshToken.ValidTo,
                            Created = DateTime.UtcNow
                        });

                var data = await connection.QueryAsync("SELECT * FROM RefreshTokens WHERE Id = @Id", new { Id = id });

                var entities =
                    data.Select(
                        x =>
                        new SqlRefreshToken()
                        {
                            ClientId = x.ClientId,
                            Created = x.Created,
                            Id = x.Id,
                            RedirectUri = x.RedirectUri,
                            Subject = x.Subject,
                            Token = x.Token,
                            ValidTo = x.ValidTo,
                            Scope = x.Scope != null ? x.Scope.ToString().Split(' ') : new string[0]
                        });

                return entities.FirstOrDefault();
            }
        }
        /// <summary>
        /// Deletes the specified refresh token. Called when authenticating a refresh token to prevent re-
        /// use.
        /// </summary>
        /// <param name="refreshToken">The refresh token.</param>
        /// <returns><c>True</c> if successful, <c>false</c> otherwise.</returns>
        public async Task<bool> DeleteRefreshToken(IRefreshToken refreshToken)
        {
            var token = (SqlRefreshToken)refreshToken;

            using (var connection = this.OpenConnection())
            {
                var rows =
                    await
                    connection.ExecuteAsync(
                        "DELETE FROM RefreshTokens WHERE Id = @Id",
                        new { Id = token.Id });

                return rows == 1;
            }
        }
        /// <summary>Inserts the specified refresh token.</summary>
        /// <param name="refreshToken">The refresh token.</param>
        /// <returns>
        ///     The inserted refresh token. <c>null</c> if the insertion was unsuccessful.
        /// </returns>
        public async Task<IRefreshToken> InsertRefreshToken(IRefreshToken refreshToken)
        {
            var token = (RefreshToken)refreshToken;

            if (this.refreshTokens.TryAdd(Guid.NewGuid(), token))
            {
                return refreshToken;
            }

            return null;
        }
        /// <summary>Deletes the specified refresh token.</summary>
        /// <param name="refreshToken">The refresh token.</param>
        /// <returns><c>True</c> if successful, <c>false</c> otherwise.</returns>
        public async Task<bool> DeleteRefreshToken(IRefreshToken refreshToken)
        {
            var exists = this.refreshTokens.Any(x => x.Value.Equals(refreshToken));

            if (exists)
            {
                var token = this.refreshTokens.First(x => x.Value.Equals(refreshToken));

                RefreshToken removedToken;
                return this.refreshTokens.TryRemove(token.Key, out removedToken);
            }

            return false;
        }
        /// <summary>
        /// Deletes the specified refresh token. Called when authenticating a refresh token to prevent re-
        /// use.
        /// </summary>
        /// <param name="refreshToken">The refresh token.</param>
        /// <returns><c>True</c> if successful, <c>false</c> otherwise.</returns>
        public async Task<bool> DeleteRefreshToken(IRefreshToken refreshToken)
        {
            var token = (RavenRefreshToken)refreshToken;

            using (var session = this.OpenAsyncSession())
            {
                var match = await session.LoadAsync<RavenRefreshToken>(token.Id);

                session.Delete(match);
                await session.SaveChangesAsync();

                return true;
            }
        }
 public Task SaveRefreshToken(IRefreshToken token)
 {
     _refreshTokens.Add(token);
     return(Task.FromResult(token));
 }
        /// <summary>Inserts the specified refresh token. Called when creating a refresh token.</summary>
        /// <param name="refreshToken">The refresh token.</param>
        /// <returns>The inserted refresh token. <c>null</c> if the insertion was unsuccessful.</returns>
        public async Task<IRefreshToken> InsertRefreshToken(IRefreshToken refreshToken)
        {
            var token = (RavenRefreshToken)refreshToken;

            using (var session = this.OpenAsyncSession())
            {
                await session.StoreAsync(token);
                await session.SaveChangesAsync();

                return refreshToken;
            }
        }
Esempio n. 10
0
 public RefreshResponse(IRefreshToken refreshToken, IAudience audience)
 {
     this.RefreshToken = refreshToken;
     this.Audience     = audience;
 }
        /// <summary>
        /// Deletes the specified refresh token. Called when authenticating a refresh token to prevent re-
        /// use.
        /// </summary>
        /// <param name="refreshToken">The refresh token.</param>
        /// <returns><c>True</c> if successful, <c>false</c> otherwise.</returns>
        public async Task<bool> DeleteRefreshToken(IRefreshToken refreshToken)
        {
            var token = (RedisRefreshToken)refreshToken;

            var key = this.GenerateKey(token);

            var db = this.GetDatabase();

            // Remove items from set
            // We don't need to remove the keys themselves, as Redis will remove them for us because we set the EXPIRE parameter.
            return await db.SortedSetRemoveAsync(this.Configuration.RefreshTokenPrefix, key);
        }
        /// <summary>Inserts the specified refresh token. Called when creating a refresh token.</summary>
        /// <param name="refreshToken">The refresh token.</param>
        /// <returns>The inserted refresh token. <c>null</c> if the insertion was unsuccessful.</returns>
        public async Task<IRefreshToken> InsertRefreshToken(IRefreshToken refreshToken)
        {
            var token = (RedisRefreshToken)refreshToken;

            var key = this.GenerateKey(token);

            var db = this.GetDatabase();

            try
            {
                if (token.ClientId == null || (token.RedirectUri == null && token.Scope == null) || token.Subject == null
                    || token.Token == null
                    || token.Created == DateTime.MinValue
                    || token.ValidTo == DateTime.MinValue)
                {
                    throw new ArgumentException(string.Format("The refresh token is invalid: {0}", JsonConvert.SerializeObject(token)), "refreshToken");
                }

                this.Configuration.Log.DebugFormat("Inserting refresh token hash in key {0}", key);

                // Add hash to key
                await db.HashSetAsync(key, token.ToHashEntries());

                var expires = refreshToken.ValidTo.ToUnixTime();

                this.Configuration.Log.DebugFormat("Inserting key {0} to refresh token set with score {1}", key, expires);

                // Add key to sorted set for future reference. The score is the expire time in seconds since epoch.
                await db.SortedSetAddAsync(this.Configuration.RefreshTokenPrefix, key, expires);

                this.Configuration.Log.DebugFormat("Making key {0} expire at {1}", key, refreshToken.ValidTo);

                // Make the key expire when the code times out
                await db.KeyExpireAsync(key, refreshToken.ValidTo);

                return refreshToken;
            }
            catch (Exception ex)
            {
                this.Configuration.Log.Error("Error when inserting refresh token", ex);
            }

            return null;
        }
Esempio n. 13
0
        public void Authorize(HttpContext context, IDictionary <string, string> query)
        {
            string refreshToken;
            string clientId       = "";
            string clientSecret   = "";
            string username       = "";
            string userPassword   = "";
            string requestedScope = "";

            //expected but already parsed input is: grant_type
            //expected input is: refresh token
            //expected input is (if enabled): client ID
            //expected input is (if enabled): client secret
            //expected input is (if enabled): user ID
            //expected input is (if enabled): user password
            //optional input is: scope

            //load refresh token
            if (query.ContainsKey("refresh_token"))
            {
                refreshToken = query["refresh_token"];
            }
            else
            {
                InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                errorResponse.Error             = InvalidAuthorizationResponse.INVALID_REQUEST;
                errorResponse.Error_description = "The refresh token is missing. The request must include the query parameter 'refresh_token'";
                //TODO: add URI
                context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                context.Response.Status = HttpStatus.BadRequest;
                return;
            }

            //load client ID
            if (query.ContainsKey("client_id"))
            {
                clientId = query["client_id"];
            }

            //load client secret
            if (query.ContainsKey("client_secret"))
            {
                clientSecret = query["client_secret"];
            }

            //load user ID
            if (query.ContainsKey("username"))
            {
                username = query["username"];
            }

            //load user password
            if (query.ContainsKey("password"))
            {
                userPassword = query["password"];
            }

            //load scope
            if (query.ContainsKey("scope"))
            {
                requestedScope = query["scope"];
            }

            //step 1: load refresh token and check whether the refresh token is listed and is valid
            IRefreshToken refreshTokenSet = _refreshStorage.GetRefreshToken(refreshToken);

            if (refreshTokenSet == null || refreshTokenSet.IsInvalidated)
            {
                InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                errorResponse.Error             = InvalidAuthorizationResponse.INVALID_CLIENT;
                errorResponse.Error_description = "The refresh token is invalid";
                //TODO: add uri
                context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                context.Response.Status = HttpStatus.Unauthorized;
                return;
            }
            //step 2: check whether the refresh token has expired
            if (refreshTokenSet.ValidUntil > 0 && refreshTokenSet.ValidUntil < DateTimeOffset.UtcNow.ToUnixTimeSeconds())
            {
                InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                errorResponse.Error             = InvalidAuthorizationResponse.INVALID_CLIENT;
                errorResponse.Error_description = "The refresh token has expired";
                //TODO: add uri
                context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                context.Response.Status = HttpStatus.Unauthorized;
                return;
            }

            //step 3: load client and check whether the client is blocked
            IClientAccount client = _clientStorage.GetClient(refreshTokenSet.ClientId);

            if (client == null || client.IsBlocked)
            {
                InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                errorResponse.Error             = InvalidAuthorizationResponse.INVALID_CLIENT;
                errorResponse.Error_description = "The refresh token has been issued to a client which is not existing or has been blocked";
                //TODO: add URI
                context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                context.Response.Status = HttpStatus.Unauthorized;
                return;
            }

            //step 3a (if enabled): check whether client is linked to the refresh token
            if (client.IsClientIdRequiredForRefreshToken)
            {
                if (String.IsNullOrWhiteSpace(clientId))
                {
                    InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                    errorResponse.Error             = InvalidAuthorizationResponse.INVALID_REQUEST;
                    errorResponse.Error_description = "The client ID is missing. The request must include the query parameter 'client_id'";
                    //TODO: add URI
                    context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                    context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                    context.Response.Status = HttpStatus.BadRequest;
                    return;
                }
                if (client.ClientId.CompareTo(clientId) != 0)
                {
                    InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                    errorResponse.Error             = InvalidAuthorizationResponse.INVALID_CLIENT;
                    errorResponse.Error_description = "The client ID is invalid";
                    //TODO: add URI
                    context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                    context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                    context.Response.Status = HttpStatus.Unauthorized;
                    return;
                }
            }

            //step 3b (if enabled): check whether client secret is valid
            if (client.IsClientSecretRequiredForRefreshToken)
            {
                if (String.IsNullOrWhiteSpace(clientSecret))
                {
                    InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                    errorResponse.Error             = InvalidAuthorizationResponse.INVALID_REQUEST;
                    errorResponse.Error_description = "The client secret is missing. The request must include the query parameter 'client_secret'";
                    //TODO: add URI
                    context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                    context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                    context.Response.Status = HttpStatus.BadRequest;
                    return;
                }
                if (client.ClientSecret.CompareTo(clientSecret) != 0)
                {
                    InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                    errorResponse.Error             = InvalidAuthorizationResponse.INVALID_CLIENT;
                    errorResponse.Error_description = "The client ID or secret is invalid";
                    //TODO: add URI
                    context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                    context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                    context.Response.Status = HttpStatus.Unauthorized;
                    return;
                }
            }

            IUserAccount user = null;

            if (client.HasUser)
            {
                //step 4a: check whether the refresh token has been issued to a user
                if (String.IsNullOrWhiteSpace(refreshTokenSet.Subject))
                {
                    InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                    errorResponse.Error             = InvalidAuthorizationResponse.INVALID_CLIENT;
                    errorResponse.Error_description = "The refresh token is invalid";
                    //TODO: add uri
                    context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                    context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                    context.Response.Status = HttpStatus.Unauthorized;
                    return;
                }

                user = _userStorage.GetUserByName(refreshTokenSet.Subject);
                //step 4b: check whether the user is existing and not blocked
                if (user == null || user.IsBlocked)
                {
                    InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                    errorResponse.Error             = InvalidAuthorizationResponse.INVALID_CLIENT;
                    errorResponse.Error_description = "The refresh token has been issued to a user which is not existing or has been blocked";
                    //TODO: add URI
                    context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                    context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                    context.Response.Status = HttpStatus.Unauthorized;
                    return;
                }

                //step 4c: check whether the linked subject (user ID) matches the passed user ID (if enabled)
                if (client.IsUserIdRequiredForRefreshToken)
                {
                    if (String.IsNullOrWhiteSpace(username))
                    {
                        InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                        errorResponse.Error             = InvalidAuthorizationResponse.INVALID_REQUEST;
                        errorResponse.Error_description = "The username is missing. The request must include the query parameter 'username'";
                        //TODO: add URI
                        context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                        context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                        context.Response.Status = HttpStatus.BadRequest;
                        return;
                    }

                    if (refreshTokenSet.Subject.CompareTo(username) != 0)
                    {
                        InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                        errorResponse.Error             = InvalidAuthorizationResponse.INVALID_CLIENT;
                        errorResponse.Error_description = "The username is invalid";
                        //TODO: add URI
                        context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                        context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                        context.Response.Status = HttpStatus.Unauthorized;
                        return;
                    }
                }

                //step 4d: check whether the passed user password is correct (if enabled)
                if (client.IsUserPasswordRequiredForRefreshToken)
                {
                    if (String.IsNullOrWhiteSpace(userPassword))
                    {
                        InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                        errorResponse.Error             = InvalidAuthorizationResponse.INVALID_REQUEST;
                        errorResponse.Error_description = "The password is missing. The request must include the query parameter 'password'";
                        //TODO: add URI
                        context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                        context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                        context.Response.Status = HttpStatus.BadRequest;
                        return;
                    }

                    if (user.Password.CompareTo(userPassword) != 0)
                    {
                        InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                        errorResponse.Error             = InvalidAuthorizationResponse.INVALID_CLIENT;
                        errorResponse.Error_description = "The username or password is invalid";
                        //TODO: add URI
                        context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                        context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                        context.Response.Status = HttpStatus.Unauthorized;
                        return;
                    }
                }
            }
            else
            {
                //check whether client has NO user, but the refresh token has been issued to a user:
                if (!String.IsNullOrWhiteSpace(refreshTokenSet.Subject))
                {
                    InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                    errorResponse.Error             = InvalidAuthorizationResponse.INVALID_CLIENT;
                    errorResponse.Error_description = "The refresh token is invalid";
                    //TODO: add uri
                    context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                    context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                    context.Response.Status = HttpStatus.Unauthorized;
                    return;
                }
            }

            //step 4: check scope
            string finalScope = "";

            if (String.IsNullOrWhiteSpace(requestedScope))
            {
                finalScope = refreshTokenSet.Scope;
            }
            else
            {
                //extract single scopes from requested scope
                string[] scopes;
                if (requestedScope.Contains(","))
                {
                    scopes = requestedScope.Split(',');
                }
                else if (requestedScope.Contains(";"))
                {
                    scopes = requestedScope.Split(';');
                }
                else if (requestedScope.Contains(" "))
                {
                    scopes = requestedScope.Split(' ');
                }
                else
                {
                    scopes = new string[] { requestedScope };
                }

                //check whether all requested scopes are permitted:
                IList <string> permittedScope = refreshTokenSet.GetScopeAsList;
                foreach (string scope in scopes)
                {
                    if (!permittedScope.Contains(scope))
                    {
                        InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                        errorResponse.Error             = InvalidAuthorizationResponse.INVALID_SCOPE;
                        errorResponse.Error_description = "The scope '" + scope + "' is not permitted or unknown";
                        //TODO: add URL
                        context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                        context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                        context.Response.Status = HttpStatus.BadRequest;
                        return;
                    }
                    finalScope += scope + " ";
                }
                finalScope.Trim();
            }

            //step 5: create new access token and issue new refresh token (if enabled and applicable)
            string subject;

            if (user == null)
            {
                subject = null;
            }
            else
            {
                subject = user.Username;
            }

            AccessToken accessToken = _reference.GenerateAccessToken(subject, clientId, finalScope, client.AccessTokenExpiryInSeconds);

            if (_issuesNewRefreshToken && refreshTokenSet.ValidUntil - DateTimeOffset.UtcNow.ToUnixTimeSeconds() < _newRefreshTokenExpiryThreshold)
            {
                accessToken.RefreshToken = _reference.GenerateRefreshToken(subject, client.ClientId, finalScope, client.RefreshTokenExpiryInSeconds);
            }
            else
            {
                accessToken.RefreshToken = null;
            }
            context.Response.Payload.Write(JsonSerializer.SerializeJson(accessToken));
            context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
            context.Response.Headers.Set("Cache-Control", "no-store");
            context.Response.Headers.Set("Pragma", "no-cache");
            context.Response.Status = HttpStatus.OK;
        }