예제 #1
0
		/// <summary>
		/// Called when the Provider is preparing to send a response to an authentication request.
		/// </summary>
		/// <param name="request">The request that is configured to generate the outgoing response.</param>
		/// <param name="cancellationToken">The cancellation token.</param>
		/// <returns>
		/// 	<c>true</c> if this behavior owns this request and wants to stop other behaviors
		/// from handling it; <c>false</c> to allow other behaviors to process this request.
		/// </returns>
		async Task<bool> IProviderBehavior.OnOutgoingResponseAsync(Provider.IAuthenticationRequest request, CancellationToken cancellationToken) {
			bool result = false;

			// Nothing to do for negative assertions.
			if (!request.IsAuthenticated.Value) {
				return result;
			}

			var requestInternal = (Provider.AuthenticationRequest)request;
			var responseMessage = (IProtocolMessageWithExtensions)await requestInternal.GetResponseAsync(cancellationToken);

			// Only apply our special policies if the RP requested it.
			var papeRequest = request.GetExtension<PolicyRequest>();
			if (papeRequest != null) {
				var papeResponse = responseMessage.Extensions.OfType<PolicyResponse>().SingleOrDefault();
				if (papeResponse == null) {
					request.AddResponseExtension(papeResponse = new PolicyResponse());
				}

				if (papeRequest.PreferredPolicies.Contains(AuthenticationPolicies.USGovernmentTrustLevel1)) {
					result = true;
					if (!papeResponse.ActualPolicies.Contains(AuthenticationPolicies.USGovernmentTrustLevel1)) {
						papeResponse.ActualPolicies.Add(AuthenticationPolicies.USGovernmentTrustLevel1);
					}

					// The spec requires that the OP perform discovery and if that fails, it must either sternly
					// warn the user of a potential threat or just abort the authentication.
					// We can't verify that the OP displayed anything to the user at this level, but we can
					// at least verify that the OP performed the discovery on the realm and halt things if it didn't.
					ErrorUtilities.VerifyHost(requestInternal.HasRealmDiscoveryBeenPerformed, BehaviorStrings.RealmDiscoveryNotPerformed);
				}

				if (papeRequest.PreferredPolicies.Contains(AuthenticationPolicies.PrivatePersonalIdentifier)) {
					ErrorUtilities.VerifyProtocol(request.ClaimedIdentifier == request.LocalIdentifier, OpenIdStrings.DelegatingIdentifiersNotAllowed);

					// Mask the user's identity with a PPID.
					ErrorUtilities.VerifyHost(PpidIdentifierProvider != null, BehaviorStrings.PpidProviderNotGiven);
					Identifier ppidIdentifier = PpidIdentifierProvider.GetIdentifier(request.LocalIdentifier, request.Realm);
					requestInternal.ResetClaimedAndLocalIdentifiers(ppidIdentifier);

					// Indicate that the RP is receiving a PPID claimed_id
					if (!papeResponse.ActualPolicies.Contains(AuthenticationPolicies.PrivatePersonalIdentifier)) {
						papeResponse.ActualPolicies.Add(AuthenticationPolicies.PrivatePersonalIdentifier);
					}
				}

				if (papeRequest.PreferredPolicies.Contains(AuthenticationPolicies.NoPersonallyIdentifiableInformation)) {
					ErrorUtilities.VerifyProtocol(
						!responseMessage.Extensions.OfType<ClaimsResponse>().Any() &&
						!responseMessage.Extensions.OfType<FetchResponse>().Any(),
						BehaviorStrings.PiiIncludedWithNoPiiPolicy);

					// If no PII is given in extensions, and the claimed_id is a PPID, then we can state we issue no PII.
					if (papeResponse.ActualPolicies.Contains(AuthenticationPolicies.PrivatePersonalIdentifier)) {
						if (!papeResponse.ActualPolicies.Contains(AuthenticationPolicies.NoPersonallyIdentifiableInformation)) {
							papeResponse.ActualPolicies.Add(AuthenticationPolicies.NoPersonallyIdentifiableInformation);
						}
					}
				}

				Reporting.RecordEventOccurrence(this, "OP");
			}

			return result;
		}