public AssociateResponse(OpenIdRelyingParty relyingParty, ServiceEndpoint provider, IDictionary <string, string> args, DiffieHellman dh) : base(relyingParty, provider, args) { DH = dh; if (Args.ContainsKey(Protocol.openidnp.assoc_handle)) { initializeAssociation(); } else { // Attempt to recover from an unsupported assoc_type if (Protocol.Version.Major >= 2) { if (Util.GetRequiredArg(Args, Protocol.openidnp.error_code) == Protocol.Args.ErrorCode.UnsupportedType) { string assoc_type = Util.GetRequiredArg(Args, Protocol.openidnp.assoc_type); string session_type = Util.GetRequiredArg(Args, Protocol.openidnp.session_type); // If the suggested options are among those we support... if (Array.IndexOf(Protocol.Args.SignatureAlgorithm.All, assoc_type) >= 0 && Array.IndexOf(Protocol.Args.SessionType.All, session_type) >= 0 && RelyingParty.Settings.IsAssociationInPermittedRange(Protocol, assoc_type)) { SecondAttempt = AssociateRequest.Create(RelyingParty, Provider, assoc_type, session_type, false); } } } } }
static Association getAssociation(OpenIdRelyingParty relyingParty, ServiceEndpoint provider, bool createNewAssociationIfNeeded) { if (relyingParty == null) { throw new ArgumentNullException("relyingParty"); } if (provider == null) { throw new ArgumentNullException("provider"); } // If the RP has no application store for associations, there's no point in creating one. if (relyingParty.Store == null) { return(null); } // TODO: we need a way to lookup an association that fulfills a given set of security // requirements. We may have a SHA-1 association and a SHA-256 association that need // to be called for specifically. (a bizzare scenario, admittedly, making this low priority). Association assoc = relyingParty.Store.GetAssociation(provider.ProviderEndpoint); // If the returned association does not fulfill security requirements, ignore it. if (assoc != null && !relyingParty.Settings.IsAssociationInPermittedRange(provider.Protocol, assoc.GetAssociationType(provider.Protocol))) { assoc = null; } if ((assoc == null || !assoc.HasUsefulLifeRemaining) && createNewAssociationIfNeeded) { var req = AssociateRequest.Create(relyingParty, provider); if (req == null) { // this can happen if security requirements and protocol conflict // to where there are no association types to choose from. return(null); } if (req.Response != null) { // try again if we failed the first time and have a worthy second-try. if (req.Response.Association == null && req.Response.SecondAttempt != null) { //Logger.Warn("Initial association attempt failed, but will retry with Provider-suggested parameters."); req = req.Response.SecondAttempt; } assoc = req.Response.Association; // Confirm that the association matches the type we requested (section 8.2.1) // if this is a 2.0 OP (1.x OPs had freedom to differ from the requested type). if (assoc != null && provider.Protocol.Version.Major >= 2) { if (!string.Equals( req.Args[provider.Protocol.openid.assoc_type], Util.GetRequiredArg(req.Response.Args, provider.Protocol.openidnp.assoc_type), StringComparison.Ordinal) || !string.Equals( req.Args[provider.Protocol.openid.session_type], Util.GetRequiredArg(req.Response.Args, provider.Protocol.openidnp.session_type), StringComparison.Ordinal)) { //Logger.ErrorFormat("Provider responded with contradicting association parameters. Requested [{0}, {1}] but got [{2}, {3}] back.", // req.Args[provider.Protocol.openid.assoc_type], // req.Args[provider.Protocol.openid.session_type], // Util.GetRequiredArg(req.Response.Args, provider.Protocol.openidnp.assoc_type), // Util.GetRequiredArg(req.Response.Args, provider.Protocol.openidnp.session_type)); assoc = null; } } if (assoc != null) { //Logger.InfoFormat("Association with {0} established.", provider.ProviderEndpoint); relyingParty.Store.StoreAssociation(provider.ProviderEndpoint, assoc); } else { //Logger.ErrorFormat("Association attempt with {0} provider failed.", provider.ProviderEndpoint); } } } return(assoc); }