/* * Copyright 2018 Amazon.com, Inc. or its affiliates. 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. * A copy of the License is located at * * http://aws.amazon.com/apache2.0 * * or in the "license" file accompanying this file. This file 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 Amazon.AspNetCore.Identity.Cognito.Exceptions; using Amazon.CognitoIdentityProvider; using Amazon.CognitoIdentityProvider.Model; using Amazon.Extensions.CognitoAuthentication; using Microsoft.AspNetCore.Identity; using System; using System.Collections.Generic; using System.Linq; using System.Security.Claims; using System.Threading; using System.Threading.Tasks; namespace Amazon.AspNetCore.Identity.Cognito { public partial class CognitoUserStore : IUserClaimStore where TUser : CognitoUser { /// /// Gets a list of s to be belonging to the specified as an asynchronous operation. /// /// The role whose claims to retrieve. /// /// A that represents the result of the asynchronous query, a list of s. /// public virtual async Task> GetClaimsAsync(TUser user, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (user == null) { throw new ArgumentNullException(nameof(user)); } try { var details = await _cognitoClient.AdminGetUserAsync(new AdminGetUserRequest { Username = user.Username, UserPoolId = _pool.PoolID }, cancellationToken).ConfigureAwait(false); return details.UserAttributes.Select(att => new Claim(att.Name, att.Value)).ToList(); } catch (AmazonCognitoIdentityProviderException e) { throw new CognitoServiceException("Failed to retrieve Cognito User claims", e); } } /// /// Add claims to a user as an asynchronous operation. /// /// The user to add the claim to. /// The collection of s to add. /// The task object representing the asynchronous operation. public virtual async Task AddClaimsAsync(TUser user, IEnumerable claims, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (user == null) { throw new ArgumentNullException(nameof(user)); } if (claims == null) { throw new ArgumentNullException(nameof(claims)); } if (claims.Any()) { try { await _cognitoClient.AdminUpdateUserAttributesAsync(new AdminUpdateUserAttributesRequest { UserAttributes = CreateAttributeList(claims.ToDictionary(claim => claim.Type, claim => claim.Value)), Username = user.Username, UserPoolId = _pool.PoolID }, cancellationToken).ConfigureAwait(false); } catch (AmazonCognitoIdentityProviderException e) { throw new CognitoServiceException("Failed to add a claim to the Cognito User", e); } } } /// /// Replaces the given on the specified with the /// /// The user to replace the claim on. /// The claim to replace. /// The new claim to replace the existing with. /// The task object representing the asynchronous operation. public Task ReplaceClaimAsync(TUser user, Claim claim, Claim newClaim, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); throw new NotSupportedException("Cognito does not support replacing claims. Call RemoveClaimsAsync() and AddClaimsAsync() instead."); } /// /// Removes the specified from the given . /// /// The user to remove the specified from. /// A collection of s to remove. /// The task object representing the asynchronous operation. public virtual async Task RemoveClaimsAsync(TUser user, IEnumerable claims, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (user == null) { throw new ArgumentNullException(nameof(user)); } if (claims == null) { throw new ArgumentNullException(nameof(claims)); } var userClaims = await GetClaimsAsync(user, cancellationToken).ConfigureAwait(false); // Only removes the claims that the user actually have. var matchedClaims = userClaims.Select(claim => new { claim.Type, claim.Value }) .Intersect(claims.Select(claim => new { claim.Type, claim.Value })); if (matchedClaims.Any()) { try { await _cognitoClient.AdminDeleteUserAttributesAsync(new AdminDeleteUserAttributesRequest { UserAttributeNames = matchedClaims.Select(claim => claim.Type).ToList(), Username = user.Username, UserPoolId = _pool.PoolID }, cancellationToken).ConfigureAwait(false); } catch (AmazonCognitoIdentityProviderException e) { throw new CognitoServiceException("Failed to remove a claim from the Cognito User", e); } } } /// /// Returns a list of users who contain the specified . /// /// The claim to look for. /// /// A that represents the result of the asynchronous query, a list of who /// contain the specified claim. /// public async Task> GetUsersForClaimAsync(Claim claim, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (claim == null) { throw new ArgumentNullException(nameof(claim)); } if (CognitoAttribute.FilterableAttributes.Contains(claim.Type)) { try { var response = await _cognitoClient.ListUsersAsync(new ListUsersRequest { Filter = claim.Type + "=\"" + claim.Value + "\"", UserPoolId = _pool.PoolID }, cancellationToken).ConfigureAwait(false); return response.Users.Select(user => _pool.GetUser(user.Username, user.UserStatus, user.Attributes.ToDictionary(att => att.Name, att => att.Value))).ToList() as IList; } catch (AmazonCognitoIdentityProviderException e) { throw new CognitoServiceException("Failed to get the list of users for a specific claim", e); } } else { throw new NotSupportedException(String.Format("Retrieving the list of users with the claim type {0} is not supported", claim.Type)); } } } }