public async Task <AuthorizeResult> GenerateTokenForIdentityId(Guid identityId, CancellationToken cancellationToken = default(CancellationToken))
        {
            var retrieveOperation = TableOperation.Retrieve <AzureIdentityEntity>(Constants.PartitionNames.IdentityPrimary, identityId.ToString());
            var retrievedResult   = await this.IdentityTable.ExecuteAsync(retrieveOperation, null, null, cancellationToken).ConfigureAwait(false);

            var retrievedEntity = (AzureIdentityEntity)retrievedResult?.Result;

            var token       = Security.GenerateToken();
            var tokenEntity = new AzureTokenEntity
            {
                IdentityId = retrievedEntity.IdentityId,
                Token      = token
            };

            var createTokenOperation = TableOperation.Insert(tokenEntity);

            await this.TokenTable.ExecuteAsync(createTokenOperation, null, null, cancellationToken).ConfigureAwait(false);

            return(new AuthorizeResult
            {
                Success = true,
                Token = token,
                IdentityId = identityId
            });
        }
        public async Task DeleteToken(string token, CancellationToken cancellationToken = default(CancellationToken))
        {
            var deleteEntity = new AzureTokenEntity
            {
                PartitionKey = Constants.PartitionNames.TokenPrimary,
                RowKey       = token,
                ETag         = "*"
            };

            var deleteOperation = TableOperation.Delete(deleteEntity);
            var result          = await this.TokenTable.ExecuteAsync(deleteOperation, null, null, cancellationToken).ConfigureAwait(false);
        }
        public async Task <CreateIdentityResult> CreateIdentity(string emailAddress, string password, CancellationToken cancellationToken = default(CancellationToken))
        {
            try
            {
                emailAddress = emailAddress?.ToLowerInvariant();

                var identityExistsCheck = await CheckIdentityExists(emailAddress, cancellationToken).ConfigureAwait(false);

                if (identityExistsCheck)
                {
                    return(new CreateIdentityResult
                    {
                        Success = false
                    });
                }

                // Identity generation
                var perUserSalt    = Security.GeneratePerUserSalt();
                var hashedPassword = Security.GeneratePasswordHash(password, perUserSalt);
                var identityEntity = new AzureIdentityEntity()
                {
                    IdentityId     = Guid.NewGuid(),
                    EmailAddress   = emailAddress,
                    PerUserSalt    = perUserSalt,
                    HashedPassword = hashedPassword
                };

                var createIdentityOperation = TableOperation.Insert(identityEntity);

                // Identity foreign key generation
                var foreignKey = new AzureIdentityForeignKeyEntity
                {
                    IdentityId   = identityEntity.IdentityId,
                    EmailAddress = emailAddress,
                };

                var createForeignKeyOperation = TableOperation.Insert(foreignKey);

                // Insert identity information
                await this.IdentityTable.ExecuteAsync(createForeignKeyOperation, null, null, cancellationToken).ConfigureAwait(false);                 // This insert first to ensure there isn't a key conflict

                await this.IdentityTable.ExecuteAsync(createIdentityOperation, null, null, cancellationToken).ConfigureAwait(false);

                // Create verification token if email provider is set up
                if (this.EmailProvider != null)
                {
                    await this.EmailProvider.SendVerificationEmail(identityEntity.IdentityId, this.EmailProvider.VerificationEmailSubject, cancellationToken).ConfigureAwait(false);

                    // Do not create token until identity is verified
                    return(new CreateIdentityResult
                    {
                        Success = true,
                        IdentityId = identityEntity.IdentityId
                    });
                }

                // Token generation
                var token       = Security.GenerateToken();
                var tokenEntity = new AzureTokenEntity
                {
                    IdentityId = identityEntity.IdentityId,
                    Token      = token
                };

                var createTokenOperation = TableOperation.Insert(tokenEntity);
                await this.TokenTable.ExecuteAsync(createTokenOperation, null, null, cancellationToken).ConfigureAwait(false);

                return(new CreateIdentityResult
                {
                    Success = true,
                    IdentityId = identityEntity.IdentityId,
                    Token = tokenEntity.Token
                });
            }
            catch (StorageException)
            {
                return(new CreateIdentityResult
                {
                    Success = false
                });
            }
        }
        public async Task <AuthorizeResult> Authorize(string emailAddress, string password, CancellationToken cancellationToken = default(CancellationToken))
        {
            try
            {
                emailAddress = emailAddress?.ToLowerInvariant();

                // Check to see if email exists
                var retrieveOperation = TableOperation.Retrieve <AzureIdentityForeignKeyEntity>(Constants.PartitionNames.EmailAddressToIdentityForeignKey, emailAddress);
                var retrievedResult   = await this.IdentityTable.ExecuteAsync(retrieveOperation, null, null, cancellationToken).ConfigureAwait(false);

                var retrievedEntity = (AzureIdentityForeignKeyEntity)retrievedResult?.Result;
                if (retrievedEntity == null)
                {
                    return(new AuthorizeResult
                    {
                        Success = false
                    });
                }

                // Retrieve IdentityEntity
                var retrieveIdentityOperation = TableOperation.Retrieve <AzureIdentityEntity>(Constants.PartitionNames.IdentityPrimary, retrievedEntity.IdentityId.ToString());
                var retrievedIdentityResult   = await this.IdentityTable.ExecuteAsync(retrieveIdentityOperation, null, null, cancellationToken).ConfigureAwait(false);

                var retrievedIdentityEntity = (AzureIdentityEntity)retrievedIdentityResult?.Result;

                if (this.EmailProvider != null && !retrievedIdentityEntity.EmailVerified && !this.AllowUnverifiedIdentities)
                {
                    return(new AuthorizeResult
                    {
                        Success = false,
                        IdentityId = retrievedEntity.IdentityId,
                        Message = "Identity has not been verified by email yet"
                    });
                }

                // Check if provided password is valid
                var passwordMatches = Security.PasswordMatches(retrievedIdentityEntity.PerUserSalt, password, retrievedIdentityEntity.HashedPassword);
                if (!passwordMatches)
                {
                    return(new AuthorizeResult
                    {
                        Success = false
                    });
                }

                // Generate, store and return token
                var token       = Security.GenerateToken();
                var tokenEntity = new AzureTokenEntity
                {
                    IdentityId = retrievedEntity.IdentityId,
                    Token      = token
                };

                var createOperation = TableOperation.Insert(tokenEntity);
                var result          = await this.TokenTable.ExecuteAsync(createOperation, null, null, cancellationToken).ConfigureAwait(false);

                return(new AuthorizeResult
                {
                    Success = true,
                    IdentityId = retrievedEntity.IdentityId,
                    Token = token
                });
            }
            catch (StorageException)
            {
                return(new AuthorizeResult
                {
                    Success = false
                });
            }
        }