| | | 1 | | // Licensed to the .NET Foundation under one or more agreements. |
| | | 2 | | // The .NET Foundation licenses this file to you under the MIT license. |
| | | 3 | | |
| | | 4 | | using System; |
| | | 5 | | using System.Collections.ObjectModel; |
| | | 6 | | using System.Globalization; |
| | | 7 | | using System.Runtime.CompilerServices; |
| | | 8 | | using System.Security.Claims; |
| | | 9 | | using System.Threading.Tasks; |
| | | 10 | | using CoreWCF.IdentityModel.Policy; |
| | | 11 | | using CoreWCF.Runtime; |
| | | 12 | | using CoreWCF.Security; |
| | | 13 | | using Microsoft.AspNetCore.Authorization; |
| | | 14 | | |
| | | 15 | | namespace CoreWCF.Dispatcher |
| | | 16 | | { |
| | | 17 | | internal sealed class AuthorizationBehavior |
| | | 18 | | { |
| | 2 | 19 | | private static readonly ServiceAuthorizationManager s_defaultServiceAuthorizationManager = new(); |
| | | 20 | | private ReadOnlyCollection<IAuthorizationPolicy> _externalAuthorizationPolicies; |
| | | 21 | | private ServiceAuthorizationManager _serviceAuthorizationManager; |
| | | 22 | | private IAuthorizationService _authorizationService; |
| | | 23 | | |
| | 266 | 24 | | private AuthorizationBehavior() { } |
| | | 25 | | |
| | | 26 | | public async ValueTask<MessageRpc> AuthorizeAsync(MessageRpc rpc) |
| | | 27 | | { |
| | | 28 | | // TODO: Events |
| | 17 | 29 | | SecurityMessageProperty security = SecurityMessageProperty.GetOrCreate(rpc.Request); |
| | 17 | 30 | | security.ExternalAuthorizationPolicies = _externalAuthorizationPolicies; |
| | | 31 | | |
| | 17 | 32 | | ServiceAuthorizationManager serviceAuthorizationManager = _serviceAuthorizationManager ?? s_defaultServiceAu |
| | | 33 | | try |
| | | 34 | | { |
| | 17 | 35 | | var checkAccessResult = await serviceAuthorizationManager.CheckAccessAsync(rpc.OperationContext, rpc.Req |
| | 17 | 36 | | rpc.Request = checkAccessResult.message; |
| | 17 | 37 | | if(!checkAccessResult.isAuthorized) |
| | | 38 | | { |
| | 2 | 39 | | throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateAccessDeniedFaultException()); |
| | | 40 | | } |
| | 15 | 41 | | } |
| | | 42 | | catch (Exception ex) |
| | | 43 | | { |
| | | 44 | | // I know this code looks weird and it looks like the try/catch block should be removed, but I'm maintai |
| | | 45 | | // this code structure in preparation for Perf counters and auditing to be put back in. |
| | 2 | 46 | | if (Fx.IsFatal(ex)) |
| | | 47 | | { |
| | 2 | 48 | | throw; |
| | | 49 | | } |
| | | 50 | | // TODO: PerformanceCounters |
| | | 51 | | // TODO: Auditing |
| | | 52 | | throw; |
| | | 53 | | } |
| | | 54 | | |
| | 15 | 55 | | return rpc; |
| | 15 | 56 | | } |
| | | 57 | | |
| | | 58 | | internal async ValueTask<MessageRpc> AuthorizePolicyAsync(MessageRpc rpc) |
| | | 59 | | { |
| | 55 | 60 | | ClaimsPrincipal principal = rpc.OperationContext.ClaimsPrincipal; |
| | 55 | 61 | | AuthorizationPolicy authorizationPolicy = rpc.Operation.AuthorizationPolicy?.Value; |
| | 55 | 62 | | if (principal != null && authorizationPolicy != null) |
| | | 63 | | { |
| | 54 | 64 | | var result = await _authorizationService.AuthorizeAsync(principal, authorizationPolicy); |
| | 54 | 65 | | if (!result.Succeeded) |
| | | 66 | | { |
| | 30 | 67 | | throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateAccessDeniedFaultException()); |
| | | 68 | | } |
| | | 69 | | } |
| | | 70 | | |
| | 25 | 71 | | return rpc; |
| | 25 | 72 | | } |
| | | 73 | | |
| | | 74 | | [MethodImpl(MethodImplOptions.NoInlining)] |
| | | 75 | | private static AuthorizationBehavior CreateAuthorizationBehavior(DispatchRuntime dispatch) |
| | | 76 | | { |
| | 133 | 77 | | AuthorizationBehavior behavior = new() |
| | 133 | 78 | | { |
| | 133 | 79 | | _externalAuthorizationPolicies = dispatch.ExternalAuthorizationPolicies, |
| | 133 | 80 | | _serviceAuthorizationManager = dispatch.ServiceAuthorizationManager, |
| | 133 | 81 | | _authorizationService = dispatch.GetAuthorizationService() |
| | 133 | 82 | | }; |
| | | 83 | | |
| | 133 | 84 | | return behavior; |
| | | 85 | | } |
| | | 86 | | |
| | | 87 | | public static AuthorizationBehavior TryCreate(DispatchRuntime dispatch) |
| | | 88 | | { |
| | 664 | 89 | | if (dispatch == null) |
| | | 90 | | { |
| | 0 | 91 | | throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(dispatch))); |
| | | 92 | | } |
| | | 93 | | |
| | 664 | 94 | | if (dispatch.SupportsAuthorizationData && !dispatch.IsAuthorizationInfrastructureRegistered()) |
| | | 95 | | { |
| | 1 | 96 | | throw new NotSupportedException(SR.AuthorizationFeaturesAuthorizationServiceIsNotRegistered); |
| | | 97 | | } |
| | | 98 | | |
| | 663 | 99 | | return dispatch switch |
| | 663 | 100 | | { |
| | 663 | 101 | | { RequiresAuthorization: true, SupportsAuthorizationData: true } => |
| | 2 | 102 | | throw new NotSupportedException(SR.AuthorizationFeaturesAreMutuallyExclusive), |
| | 663 | 103 | | { RequiresAuthorization: true } or { SupportsAuthorizationData: true } => |
| | 133 | 104 | | CreateAuthorizationBehavior(dispatch), |
| | 528 | 105 | | _ => null |
| | 663 | 106 | | }; |
| | | 107 | | } |
| | | 108 | | |
| | | 109 | | internal static Exception CreateAccessDeniedFaultException() |
| | | 110 | | { |
| | 38 | 111 | | SecurityVersion wss = SecurityVersion.Default; |
| | 38 | 112 | | FaultCode faultCode = FaultCode.CreateSenderFaultCode(wss.FailedAuthenticationFaultCode.Value, wss.HeaderNam |
| | 38 | 113 | | FaultReason faultReason = new FaultReason(SR.AccessDenied, CultureInfo.CurrentCulture); |
| | 38 | 114 | | return new FaultException(faultReason, faultCode); |
| | | 115 | | } |
| | | 116 | | } |
| | | 117 | | } |