/// <summary> /// Creates a Provider's response to an incoming association request. /// </summary> /// <param name="requestMessage">The request message.</param> /// <param name="associationStore">The association store.</param> /// <param name="securitySettings">The security settings on the Provider.</param> /// <returns> /// The appropriate association response that is ready to be sent back to the Relying Party. /// </returns> /// <remarks> /// <para>If an association is created, it will be automatically be added to the provided /// association store.</para> /// <para>Successful association response messages will derive from <see cref="AssociateSuccessfulResponse"/>. /// Failed association response messages will derive from <see cref="AssociateUnsuccessfulResponse"/>.</para> /// </remarks> internal static IProtocolMessage CreateResponse(IAssociateRequestProvider requestMessage, IProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings) { Requires.NotNull(requestMessage, "requestMessage"); Requires.NotNull(associationStore, "associationStore"); Requires.NotNull(securitySettings, "securitySettings"); AssociateRequest request = (AssociateRequest)requestMessage; IProtocolMessage response; var protocol = requestMessage.GetProtocol(); if (securitySettings.IsAssociationInPermittedRange(protocol, request.AssociationType) && HmacShaAssociation.IsDHSessionCompatible(protocol, request.AssociationType, request.SessionType)) { response = requestMessage.CreateResponseCore(); // Create and store the association if this is a successful response. var successResponse = response as IAssociateSuccessfulResponseProvider; if (successResponse != null) { OpenIdProviderUtilities.CreateAssociation(request, successResponse, associationStore, securitySettings); } } else { response = CreateUnsuccessfulResponse(requestMessage, securitySettings); } return(response); }
/// <summary> /// Creates a Provider's response to an incoming association request. /// </summary> /// <param name="associationStore">The association store where a new association (if created) will be stored. Must not be null.</param> /// <param name="securitySettings">The security settings on the Provider.</param> /// <returns> /// The appropriate association response that is ready to be sent back to the Relying Party. /// </returns> /// <remarks> /// <para>If an association is created, it will be automatically be added to the provided /// association store.</para> /// <para>Successful association response messages will derive from <see cref="AssociateSuccessfulResponse"/>. /// Failed association response messages will derive from <see cref="AssociateUnsuccessfulResponse"/>.</para> /// </remarks> internal IProtocolMessage CreateResponse(IAssociationStore <AssociationRelyingPartyType> associationStore, ProviderSecuritySettings securitySettings) { Contract.Requires <ArgumentNullException>(associationStore != null); Contract.Requires <ArgumentNullException>(securitySettings != null); IProtocolMessage response; if (securitySettings.IsAssociationInPermittedRange(Protocol, this.AssociationType) && HmacShaAssociation.IsDHSessionCompatible(Protocol, this.AssociationType, this.SessionType)) { response = this.CreateResponseCore(); // Create and store the association if this is a successful response. var successResponse = response as AssociateSuccessfulResponse; if (successResponse != null) { Association association = successResponse.CreateAssociation(this, securitySettings); associationStore.StoreAssociation(AssociationRelyingPartyType.Smart, association); } } else { response = this.CreateUnsuccessfulResponse(securitySettings); } return(response); }
/// <summary> /// Creates a new association with a given Provider. /// </summary> /// <param name="provider">The provider to create an association with.</param> /// <param name="associateRequest">The associate request. May be <c>null</c>, which will always result in a <c>null</c> return value..</param> /// <param name="retriesRemaining">The number of times to try the associate request again if the Provider suggests it.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns> /// The newly created association, or null if no association can be created with /// the given Provider given the current security settings. /// </returns> /// <exception cref="ProtocolException">Create if an error occurs while creating the new association.</exception> private async Task <Association> CreateNewAssociationAsync(IProviderEndpoint provider, AssociateRequest associateRequest, int retriesRemaining, CancellationToken cancellationToken) { Requires.NotNull(provider, "provider"); if (associateRequest == null || retriesRemaining < 0) { // this can happen if security requirements and protocol conflict // to where there are no association types to choose from. return(null); } Exception exception = null; try { var associateResponse = await this.channel.RequestAsync(associateRequest, cancellationToken); var associateSuccessfulResponse = associateResponse as IAssociateSuccessfulResponseRelyingParty; var associateUnsuccessfulResponse = associateResponse as AssociateUnsuccessfulResponse; if (associateSuccessfulResponse != null) { Association association = associateSuccessfulResponse.CreateAssociationAtRelyingParty(associateRequest); this.associationStore.StoreAssociation(provider.Uri, association); return(association); } else if (associateUnsuccessfulResponse != null) { if (string.IsNullOrEmpty(associateUnsuccessfulResponse.AssociationType)) { Logger.OpenId.Debug("Provider rejected an association request and gave no suggestion as to an alternative association type. Giving up."); return(null); } if (!this.securitySettings.IsAssociationInPermittedRange(Protocol.Lookup(provider.Version), associateUnsuccessfulResponse.AssociationType)) { Logger.OpenId.DebugFormat("Provider rejected an association request and suggested '{0}' as an association to try, which this Relying Party does not support. Giving up.", associateUnsuccessfulResponse.AssociationType); return(null); } if (retriesRemaining <= 0) { Logger.OpenId.Debug("Unable to agree on an association type with the Provider in the allowed number of retries. Giving up."); return(null); } // Make sure the Provider isn't suggesting an incompatible pair of association/session types. Protocol protocol = Protocol.Lookup(provider.Version); ErrorUtilities.VerifyProtocol( HmacShaAssociation.IsDHSessionCompatible(protocol, associateUnsuccessfulResponse.AssociationType, associateUnsuccessfulResponse.SessionType), OpenIdStrings.IncompatibleAssociationAndSessionTypes, associateUnsuccessfulResponse.AssociationType, associateUnsuccessfulResponse.SessionType); associateRequest = AssociateRequestRelyingParty.Create(this.securitySettings, provider, associateUnsuccessfulResponse.AssociationType, associateUnsuccessfulResponse.SessionType); return(await this.CreateNewAssociationAsync(provider, associateRequest, retriesRemaining - 1, cancellationToken)); } else { throw new ProtocolException(MessagingStrings.UnexpectedMessageReceivedOfMany); } } catch (ProtocolException ex) { exception = ex; } Assumes.NotNull(exception); // If the association failed because the remote server can't handle Expect: 100 Continue headers, // then our web request handler should have already accomodated for future calls. Go ahead and // immediately make one of those future calls now to try to get the association to succeed. if (UntrustedWebRequestHandler.IsExceptionFrom417ExpectationFailed(exception)) { return(await this.CreateNewAssociationAsync(provider, associateRequest, retriesRemaining - 1, cancellationToken)); } // Since having associations with OPs is not totally critical, we'll log and eat // the exception so that auth may continue in dumb mode. Logger.OpenId.ErrorFormat("An error occurred while trying to create an association with {0}. {1}", provider.Uri, exception); return(null); }
/// <summary> /// Creates a new association with a given Provider. /// </summary> /// <param name="provider">The provider to create an association with.</param> /// <param name="associateRequest">The associate request. May be <c>null</c>, which will always result in a <c>null</c> return value..</param> /// <param name="retriesRemaining">The number of times to try the associate request again if the Provider suggests it.</param> /// <returns> /// The newly created association, or null if no association can be created with /// the given Provider given the current security settings. /// </returns> private Association CreateNewAssociation(ProviderEndpointDescription provider, AssociateRequest associateRequest, int retriesRemaining) { ErrorUtilities.VerifyArgumentNotNull(provider, "provider"); if (associateRequest == null || retriesRemaining < 0) { // this can happen if security requirements and protocol conflict // to where there are no association types to choose from. return(null); } try { var associateResponse = this.channel.Request(associateRequest); var associateSuccessfulResponse = associateResponse as AssociateSuccessfulResponse; var associateUnsuccessfulResponse = associateResponse as AssociateUnsuccessfulResponse; if (associateSuccessfulResponse != null) { Association association = associateSuccessfulResponse.CreateAssociation(associateRequest, null); this.associationStore.StoreAssociation(provider.Endpoint, association); return(association); } else if (associateUnsuccessfulResponse != null) { if (string.IsNullOrEmpty(associateUnsuccessfulResponse.AssociationType)) { Logger.Debug("Provider rejected an association request and gave no suggestion as to an alternative association type. Giving up."); return(null); } if (!this.securitySettings.IsAssociationInPermittedRange(Protocol.Lookup(provider.ProtocolVersion), associateUnsuccessfulResponse.AssociationType)) { Logger.DebugFormat("Provider rejected an association request and suggested '{0}' as an association to try, which this Relying Party does not support. Giving up.", associateUnsuccessfulResponse.AssociationType); return(null); } if (retriesRemaining <= 0) { Logger.Debug("Unable to agree on an association type with the Provider in the allowed number of retries. Giving up."); return(null); } // Make sure the Provider isn't suggesting an incompatible pair of association/session types. Protocol protocol = Protocol.Lookup(provider.ProtocolVersion); ErrorUtilities.VerifyProtocol( HmacShaAssociation.IsDHSessionCompatible(protocol, associateUnsuccessfulResponse.AssociationType, associateUnsuccessfulResponse.SessionType), OpenIdStrings.IncompatibleAssociationAndSessionTypes, associateUnsuccessfulResponse.AssociationType, associateUnsuccessfulResponse.SessionType); associateRequest = AssociateRequest.Create(this.securitySettings, provider, associateUnsuccessfulResponse.AssociationType, associateUnsuccessfulResponse.SessionType); return(this.CreateNewAssociation(provider, associateRequest, retriesRemaining - 1)); } else { throw new ProtocolException(MessagingStrings.UnexpectedMessageReceivedOfMany); } } catch (ProtocolException ex) { // Since having associations with OPs is not totally critical, we'll log and eat // the exception so that auth may continue in dumb mode. Logger.ErrorFormat("An error occurred while trying to create an association with {0}. {1}", provider.Endpoint, ex); return(null); } }
public static AssociateRequest Create(OpenIdRelyingParty relyingParty, ServiceEndpoint provider, string assoc_type, string session_type, bool allowNoSession) { if (relyingParty == null) { throw new ArgumentNullException("relyingParty"); } if (provider == null) { throw new ArgumentNullException("provider"); } if (assoc_type == null) { throw new ArgumentNullException("assoc_type"); } if (session_type == null) { throw new ArgumentNullException("session_type"); } Debug.Assert(Array.IndexOf(provider.Protocol.Args.SignatureAlgorithm.All, assoc_type) >= 0); Debug.Assert(Array.IndexOf(provider.Protocol.Args.SessionType.All, session_type) >= 0); if (!HmacShaAssociation.IsDHSessionCompatible(provider.Protocol, assoc_type, session_type)) { throw new OpenIdException(string.Format(CultureInfo.CurrentCulture, Strings.IncompatibleAssociationAndSessionTypes, assoc_type, session_type)); } var args = new Dictionary <string, string>(); Protocol protocol = provider.Protocol; args.Add(protocol.openid.mode, protocol.Args.Mode.associate); args.Add(protocol.openid.assoc_type, assoc_type); DiffieHellman dh = null; if (provider.ProviderEndpoint.Scheme == Uri.UriSchemeHttps && allowNoSession) { Logger.InfoFormat("Requesting association with {0} (assoc_type = '{1}', session_type = '{2}').", provider.ProviderEndpoint, assoc_type, protocol.Args.SessionType.NoEncryption); args.Add(protocol.openid.session_type, protocol.Args.SessionType.NoEncryption); } else { Logger.InfoFormat("Requesting association with {0} (assoc_type = '{1}', session_type = '{2}').", provider.ProviderEndpoint, assoc_type, session_type); // Initiate Diffie-Hellman Exchange dh = DiffieHellmanUtil.CreateDiffieHellman(); byte[] dhPublic = dh.CreateKeyExchange(); string cpub = DiffieHellmanUtil.UnsignedToBase64(dhPublic); args.Add(protocol.openid.session_type, session_type); args.Add(protocol.openid.dh_consumer_public, cpub); DHParameters dhps = dh.ExportParameters(true); if (dhps.P != DiffieHellmanUtil.DEFAULT_MOD || dhps.G != DiffieHellmanUtil.DEFAULT_GEN) { args.Add(protocol.openid.dh_modulus, DiffieHellmanUtil.UnsignedToBase64(dhps.P)); args.Add(protocol.openid.dh_gen, DiffieHellmanUtil.UnsignedToBase64(dhps.G)); } } return(new AssociateRequest(relyingParty, provider, args, dh)); }