public void TestClaimCheckResponse() { byte[] input = File.ReadAllBytes("ClaimCheckResponse.xml"); var response = new ClaimCheckResponse(input); Assert.AreEqual("1000", response.Code); Assert.AreEqual("Command completed successfully", response.Message); Assert.AreEqual(2, response.Results.Count); Assert.AreEqual("example1.com", response.Results[0].Name); Assert.AreEqual(true, response.Results[0].ClaimExists); Assert.AreEqual("2016100401/2/D/7/LXsvtbnP8C5bUdxDuoj-XvJK0000000263", response.Results[0].ClaimKeys[0].Value); Assert.AreEqual("example2.com", response.Results[1].Name); Assert.AreEqual(false, response.Results[1].ClaimExists); Assert.AreEqual(0, response.Results[1].ClaimKeys.Count); }
private ClaimCheckResponse GetRelevantPrincipalClaims( IList <string> authorizingClaimNames, string requestedAction, ClaimsPrincipal principal) { var response = new ClaimCheckResponse(); // Find matching claims, while preserving the ordering of the incoming claim names var principalClaimsToEvaluate = (from cn in authorizingClaimNames join pc in principal.Claims on cn equals pc.Type select pc) .ToList(); // 1) First check: Lets make sure the principal at least has a claim that applies for this resource. if (!principalClaimsToEvaluate.Any()) { response.Success = false; var apiClientResourceClaims = principal.Claims.Select(c => c.Type) .Where(x => x.StartsWith(EdFi.Ods.Common.Conventions.EdFiConventions.EdFiOdsResourceClaimBaseUri)); string apiClientClaimSetName = principal.Claims.SingleOrDefault(c => c.Type == EdFiOdsApiClaimTypes.ClaimSetName)?.Value; response.SecurityExceptionMessage = $@"Access to the resource could not be authorized. Are you missing a claim? This resource can be authorized by the following claims: {string.Join(Environment.NewLine + " ", authorizingClaimNames)} The API client has been assigned the '{apiClientClaimSetName}' claim set with the following resource claims: {string.Join(Environment.NewLine + " ", apiClientResourceClaims)}"; return(response); } // 2) Second check: Of the claims that apply for this resource do we have any that match the action requested or a higher action? var edfiClaimValuesToEvaluate = principalClaimsToEvaluate.Select( x => new { Claim = x, EdFiResourceClaimValue = x.ToEdFiResourceClaimValue() }); var claimsWithMatchingActions = edfiClaimValuesToEvaluate.Where( x => IsRequestedActionSatisfiedByClaimActions( requestedAction, x.EdFiResourceClaimValue.Actions.Select(y => y.Name))) .ToList(); if (!claimsWithMatchingActions.Any()) { response.Success = false; response.SecurityExceptionMessage = string.Format( "Access to the resource could not be authorized for the requested action '{0}'.", requestedAction); return(response); } response.Success = true; response.RelevantClaims = claimsWithMatchingActions.Select(x => x.Claim) .ToList(); return(response); }
private ClaimCheckResponse PerformClaimCheck(EdFiAuthorizationContext authorizationContext) { // Validate the context ValidateAuthorizationContext(authorizationContext); // Extract individual values string[] requestedResourceClaimUris = authorizationContext.Resource.Select(x => x.Value).ToArray(); string requestedAction = authorizationContext.Action.Single().Value; // NOTE: GKM - Review all use of the ClaimsPrincipal, and consider eliminating it for CallContext var principal = authorizationContext.Principal; // Obtain the resource claim/authorization strategy pairs that could be used for authorizing this particular request var resourceClaimAuthorizationMetadata = GetResourceClaimAuthorizationMetadatas(requestedResourceClaimUris, requestedAction); // Get the names of the resource claims that could be used for authorization var authorizingResourceClaimNames = resourceClaimAuthorizationMetadata .Select(x => x.ClaimName) .ToList(); // Intersect the potentially authorizing resource claims against the principal's claims var claimCheckResponse = GetRelevantPrincipalClaims(authorizingResourceClaimNames, requestedAction, principal); if (claimCheckResponse.Success) { claimCheckResponse.RequestedAction = requestedAction; claimCheckResponse.RequestedResourceUris = requestedResourceClaimUris; claimCheckResponse.AuthorizationMetadata = resourceClaimAuthorizationMetadata; } return(claimCheckResponse); void ValidateAuthorizationContext(EdFiAuthorizationContext authorizationContext) { if (authorizationContext == null) { throw new ArgumentNullException("authorizationContext"); } if (authorizationContext.Resource == null || authorizationContext.Resource.All(r => string.IsNullOrWhiteSpace(r.Value))) { throw new AuthorizationContextException("Authorization can only be performed if a resource is specified."); } if (authorizationContext.Resource.Count > 2) { throw new AuthorizationContextException($"Unexpected number of Resource URIs found in the authorization context. Expected up to 2, but found {authorizationContext.Resource.Count}."); } if (authorizationContext.Action == null || authorizationContext.Action.All(a => string.IsNullOrWhiteSpace(a.Value))) { throw new AuthorizationContextException("Authorization can only be performed if an action is specified."); } if (authorizationContext.Action.Count > 1) { throw new AuthorizationContextException("Authorization can only be performed on requests with a single action."); } } List <ResourceClaimAuthorizationMetadata> GetResourceClaimAuthorizationMetadatas( string[] requestedResourceClaimUris, string requestedAction) { // Processing the URIs in order of priority, return the first one found with associated // authorization metadata var resourceClaimAuthorizationMetadata = requestedResourceClaimUris .Select( requestedResourceClaimUri => _resourceAuthorizationMetadataProvider .GetResourceClaimAuthorizationMetadata(requestedResourceClaimUri, requestedAction) .ToList()) .FirstOrDefault(x => x.Any()); // Return the authorization metadata located, or an empty list. return(resourceClaimAuthorizationMetadata ?? new List <ResourceClaimAuthorizationMetadata>()); } ClaimCheckResponse GetRelevantPrincipalClaims( IList <string> authorizingClaimNames, string requestedAction, ClaimsPrincipal principal) { var response = new ClaimCheckResponse(); // Find matching claims, while preserving the ordering of the incoming claim names var principalClaimsToEvaluate = (from cn in authorizingClaimNames join pc in principal.Claims on cn equals pc.Type select pc).ToList(); // 1) First check: Lets make sure the principal at least has a claim that applies for this resource. if (!principalClaimsToEvaluate.Any()) { response.Success = false; var apiClientResourceClaims = principal.Claims.Select(c => c.Type) .Where(x => x.StartsWith(EdFiConventions.EdFiOdsResourceClaimBaseUri)); string apiClientClaimSetName = principal.Claims.SingleOrDefault(c => c.Type == EdFiOdsApiClaimTypes.ClaimSetName)?.Value; response.SecurityExceptionMessage = $@"Access to the resource could not be authorized. Are you missing a claim? This resource can be authorized by the following claims: {string.Join(Environment.NewLine + " ", authorizingClaimNames)} The API client has been assigned the '{apiClientClaimSetName}' claim set with the following resource claims: {string.Join(Environment.NewLine + " ", apiClientResourceClaims)}"; return(response); } // 2) Second check: Of the claims that apply for this resource do we have any that match the action requested or a higher action? var edfiClaimValuesToEvaluate = principalClaimsToEvaluate.Select( x => new { Claim = x, EdFiResourceClaimValue = x.ToEdFiResourceClaimValue() }); var claimsWithMatchingActions = edfiClaimValuesToEvaluate.Where( x => IsRequestedActionSatisfiedByClaimActions( requestedAction, x.EdFiResourceClaimValue.Actions.Select(y => y.Name))) .ToList(); if (!claimsWithMatchingActions.Any()) { response.Success = false; response.SecurityExceptionMessage = string.Format( "Access to the resource could not be authorized for the requested action '{0}'.", requestedAction); return(response); } response.Success = true; response.RelevantClaims = claimsWithMatchingActions.Select(x => x.Claim).ToList(); return(response); } bool IsRequestedActionSatisfiedByClaimActions(string requestedAction, IEnumerable <string> principalClaimActions) { int requestedActionValue = GetBitValuesByAction(requestedAction); // Determine if any of the claim actions can satisfy the requested action return(principalClaimActions.Any(x => (requestedActionValue & GetBitValuesByAction(x)) != 0)); } int GetBitValuesByAction(string action) { int result; if (_bitValuesByAction.Value.TryGetValue(action, out result)) { return(result); } // Should never happen throw new NotSupportedException("The requested action is not a supported action. Authorization cannot be performed."); } }