コード例 #1
0
        public static AssociateRequest Create(OpenIdRelyingParty relyingParty, ServiceEndpoint provider)
        {
            if (relyingParty == null)
            {
                throw new ArgumentNullException("relyingParty");
            }
            if (provider == null)
            {
                throw new ArgumentNullException("provider");
            }

            string assoc_type, session_type;
            bool   requireDiffieHellman = !string.Equals(provider.ProviderEndpoint.Scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase);

            if (HmacShaAssociation.TryFindBestAssociation(provider.Protocol,
                                                          relyingParty.Settings.MinimumHashBitLength, relyingParty.Settings.MaximumHashBitLength,
                                                          requireDiffieHellman, out assoc_type, out session_type))
            {
                return(Create(relyingParty, provider, assoc_type, session_type, true));
            }
            else
            {
                // There are no associations that meet all requirements.
                //Logger.Warn("Security requirements and protocol combination knock out all possible association types.  Dumb mode forced.");
                return(null);
            }
        }
コード例 #2
0
        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);
                        }
                    }
                }
            }
        }
コード例 #3
0
        protected DirectResponse(OpenIdRelyingParty relyingParty, ServiceEndpoint provider, IDictionary <string, string> args)
        {
            if (relyingParty == null)
            {
                throw new ArgumentNullException("relyingParty");
            }
            if (provider == null)
            {
                throw new ArgumentNullException("provider");
            }
            if (args == null)
            {
                throw new ArgumentNullException("args");
            }
            RelyingParty = relyingParty;
            Provider     = provider;
            Args         = args;

            // Make sure that the OP fulfills the required OpenID version.
            // We don't use Provider.Protocol here because that's just a cache of
            // what we _thought_ the OP would support, and our purpose is to double-check this.
            ProtocolVersion detectedProtocol = Protocol.DetectFromDirectResponse(args).ProtocolVersion;

            if (detectedProtocol < relyingParty.Settings.MinimumRequiredOpenIdVersion)
            {
                throw new OpenIdException(string.Format(CultureInfo.CurrentCulture,
                                                        Strings.MinimumOPVersionRequirementNotMet,
                                                        Protocol.Lookup(relyingParty.Settings.MinimumRequiredOpenIdVersion).Version,
                                                        Protocol.Lookup(detectedProtocol).Version));
            }
        }
コード例 #4
0
        AuthenticationRequest(ServiceEndpoint endpoint,
                              Realm realm, Uri returnToUrl, OpenIdRelyingParty relyingParty)
        {
            if (endpoint == null)
            {
                throw new ArgumentNullException("endpoint");
            }
            if (realm == null)
            {
                throw new ArgumentNullException("realm");
            }
            if (returnToUrl == null)
            {
                throw new ArgumentNullException("returnToUrl");
            }
            if (relyingParty == null)
            {
                throw new ArgumentNullException("relyingParty");
            }

            this.endpoint = endpoint;
            RelyingParty  = relyingParty;
            Realm         = realm;
            ReturnToUrl   = returnToUrl;

            Mode = AuthenticationRequestMode.Setup;
            OutgoingExtensions = ExtensionArgumentsManager.CreateOutgoingExtensions(endpoint.Protocol);
            ReturnToArgs       = new Dictionary <string, string>();
        }
コード例 #5
0
        static AuthenticationResponse parseIdResResponse(IDictionary <string, string> query,
                                                         ServiceEndpoint tokenEndpoint, ServiceEndpoint responseEndpoint,
                                                         OpenIdRelyingParty relyingParty, Uri requestUrl, bool verifyMessageSignature)
        {
            // Use responseEndpoint if it is available so we get the
            // Claimed Identifer correct in the AuthenticationResponse.
            ServiceEndpoint unverifiedEndpoint = responseEndpoint ?? tokenEndpoint;

            if (unverifiedEndpoint.Protocol.Version.Major < 2)
            {
                string user_setup_url = Util.GetOptionalArg(query, unverifiedEndpoint.Protocol.openid.user_setup_url);
                if (user_setup_url != null)
                {
                    return(new AuthenticationResponse(AuthenticationStatus.SetupRequired, unverifiedEndpoint, query));
                }
            }

            verifyReturnTo(query, unverifiedEndpoint, requestUrl);
            verifyDiscoveredInfoMatchesAssertedInfo(relyingParty, query, tokenEndpoint, responseEndpoint);
            if (verifyMessageSignature)
            {
                verifyNonceUnused(query, unverifiedEndpoint, relyingParty.Store);
                verifySignature(relyingParty, query, unverifiedEndpoint);
            }

            return(new AuthenticationResponse(AuthenticationStatus.Authenticated, unverifiedEndpoint, query));
        }
コード例 #6
0
        /// <summary>
        /// Performs request generation for the <see cref="Create"/> method.
        /// All data validation and cleansing steps must have ALREADY taken place.
        /// </summary>
        private static IEnumerable <AuthenticationRequest> CreateInternal(Identifier userSuppliedIdentifier,
                                                                          OpenIdRelyingParty relyingParty, Realm realm, Uri returnToUrl,
                                                                          IEnumerable <ServiceEndpoint> serviceEndpoints, bool createNewAssociationsAsNeeded)
        {
            //Logger.InfoFormat("Performing discovery on user-supplied identifier: {0}", userSuppliedIdentifier);
            IEnumerable <ServiceEndpoint> endpoints = filterAndSortEndpoints(serviceEndpoints, relyingParty);

            // Maintain a list of endpoints that we could not form an association with.
            // We'll fallback to generating requests to these if the ones we CAN create
            // an association with run out.
            var failedAssociationEndpoints = new List <ServiceEndpoint>(0);

            foreach (var endpoint in endpoints)
            {
                //Logger.InfoFormat("Creating authentication request for user supplied Identifier: {0}", userSuppliedIdentifier);
                //Logger.DebugFormat("Realm: {0}", realm);
                //Logger.DebugFormat("Return To: {0}", returnToUrl);

                // The strategy here is to prefer endpoints with whom we can create associations.
                Association association = null;
                if (relyingParty.Store != null)
                {
                    // In some scenarios (like the AJAX control wanting ALL auth requests possible),
                    // we don't want to create associations with every Provider.  But we'll use
                    // associations where they are already formed from previous authentications.
                    association = getAssociation(relyingParty, endpoint, createNewAssociationsAsNeeded);
                    if (association == null && createNewAssociationsAsNeeded)
                    {
                        //Logger.WarnFormat("Failed to create association with {0}.  Skipping to next endpoint.", endpoint.ProviderEndpoint);
                        // No association could be created.  Add it to the list of failed association
                        // endpoints and skip to the next available endpoint.
                        failedAssociationEndpoints.Add(endpoint);
                        continue;
                    }
                }

                yield return(new AuthenticationRequest(endpoint, realm, returnToUrl, relyingParty));
            }

            // Now that we've run out of endpoints that respond to association requests,
            // since we apparently are still running, the caller must want another request.
            // We'll go ahead and generate the requests to OPs that may be down.
            if (failedAssociationEndpoints.Count > 0)
            {
                //Logger.WarnFormat("Now generating requests for Provider endpoints that failed initial association attempts.");

                foreach (var endpoint in failedAssociationEndpoints)
                {
                    //Logger.WarnFormat("Creating authentication request for user supplied Identifier: {0}", userSuppliedIdentifier);
                    //Logger.DebugFormat("Realm: {0}", realm);
                    //Logger.DebugFormat("Return To: {0}", returnToUrl);

                    // Create the auth request, but prevent it from attempting to create an association
                    // because we've already tried.  Let's not have it waste time trying again.
                    var authRequest = new AuthenticationRequest(endpoint, realm, returnToUrl, relyingParty);
                    authRequest.associationPreference = AssociationPreference.IfAlreadyEstablished;
                    yield return(authRequest);
                }
            }
        }
コード例 #7
0
        /// <summary>
        /// Performs a dumb-mode authentication verification by making an extra
        /// request to the provider after the user agent was redirected back
        /// to the consumer site with an authenticated status.
        /// </summary>
        /// <returns>Whether the authentication is valid.</returns>
        static void verifySignatureByProvider(OpenIdRelyingParty relyingParty, IDictionary <string, string> query, ServiceEndpoint provider)
        {
            var request = CheckAuthRequest.Create(relyingParty, provider, query);

            if (request.Response.InvalidatedAssociationHandle != null && relyingParty.Store != null)
            {
                relyingParty.Store.RemoveAssociation(provider.ProviderEndpoint, request.Response.InvalidatedAssociationHandle);
            }
            if (!request.Response.IsAuthenticationValid)
            {
                throw new OpenIdException(Strings.InvalidSignature);
            }
        }
コード例 #8
0
        static void verifySignature(OpenIdRelyingParty relyingParty, IDictionary <string, string> query, ServiceEndpoint endpoint)
        {
            string signed = Util.GetRequiredArg(query, endpoint.Protocol.openid.signed);

            string[] signedFields = signed.Split(',');

            // Check that all fields that are required to be signed are indeed signed
            if (endpoint.Protocol.Version.Major >= 2)
            {
                verifyFieldsAreSigned(signedFields,
                                      endpoint.Protocol.openidnp.op_endpoint,
                                      endpoint.Protocol.openidnp.return_to,
                                      endpoint.Protocol.openidnp.response_nonce,
                                      endpoint.Protocol.openidnp.assoc_handle);
                if (query.ContainsKey(endpoint.Protocol.openid.claimed_id))
                {
                    verifyFieldsAreSigned(signedFields,
                                          endpoint.Protocol.openidnp.claimed_id,
                                          endpoint.Protocol.openidnp.identity);
                }
            }
            else
            {
                verifyFieldsAreSigned(signedFields,
                                      endpoint.Protocol.openidnp.identity,
                                      endpoint.Protocol.openidnp.return_to);
            }

            // Now actually validate the signature itself.
            string      assoc_handle = Util.GetRequiredArg(query, endpoint.Protocol.openid.assoc_handle);
            Association assoc        = relyingParty.Store != null?relyingParty.Store.GetAssociation(endpoint.ProviderEndpoint, assoc_handle) : null;

            if (assoc == null)
            {
                // It's not an association we know about.  Dumb mode is our
                // only possible path for recovery.
                //Logger.Debug("Passing signature back to Provider for verification (no association available)...");
                verifySignatureByProvider(relyingParty, query, endpoint);
            }
            else
            {
                if (assoc.IsExpired)
                {
                    throw new OpenIdException(string.Format(CultureInfo.CurrentCulture,
                                                            "Association with {0} expired", endpoint.ProviderEndpoint), endpoint.ClaimedIdentifier);
                }

                //Logger.Debug("Verifying signature by association...");
                verifySignatureByAssociation(query, endpoint.Protocol, signedFields, assoc);
            }
        }
コード例 #9
0
        /// <summary>
        /// Returns a filtered and sorted list of the available OP endpoints for a discovered Identifier.
        /// </summary>
        private static List <ServiceEndpoint> filterAndSortEndpoints(IEnumerable <ServiceEndpoint> endpoints,
                                                                     OpenIdRelyingParty relyingParty)
        {
            if (endpoints == null)
            {
                throw new ArgumentNullException("endpoints");
            }
            if (relyingParty == null)
            {
                throw new ArgumentNullException("relyingParty");
            }

            // Construct the endpoints filters based on criteria given by the host web site.
            EndpointSelector versionFilter     = ep => ((ServiceEndpoint)ep).Protocol.Version >= Protocol.Lookup(relyingParty.Settings.MinimumRequiredOpenIdVersion).Version;
            EndpointSelector hostingSiteFilter = relyingParty.EndpointFilter ?? (ep => true);

            bool anyFilteredOut    = false;
            var  filteredEndpoints = new List <IXrdsProviderEndpoint>();

            foreach (ServiceEndpoint endpoint in endpoints)
            {
                if (versionFilter(endpoint) && hostingSiteFilter(endpoint))
                {
                    filteredEndpoints.Add(endpoint);
                }
                else
                {
                    anyFilteredOut = true;
                }
            }

            // Sort endpoints so that the first one in the list is the most preferred one.
            filteredEndpoints.Sort(relyingParty.EndpointOrder);

            List <ServiceEndpoint> endpointList = new List <ServiceEndpoint>(filteredEndpoints.Count);

            foreach (ServiceEndpoint endpoint in filteredEndpoints)
            {
                endpointList.Add(endpoint);
            }

            if (anyFilteredOut)
            {
                //Logger.DebugFormat("Some endpoints were filtered out.  Total endpoints remaining: {0}", filteredEndpoints.Count);
            }


            return(endpointList);
        }
コード例 #10
0
        /// <summary>
        /// Performs identifier discovery and creates associations and generates authentication requests
        /// on-demand for as long as new ones can be generated based on the results of Identifier discovery.
        /// </summary>
        internal static IEnumerable <AuthenticationRequest> Create(Identifier userSuppliedIdentifier,
                                                                   OpenIdRelyingParty relyingParty, Realm realm, Uri returnToUrl, bool createNewAssociationsAsNeeded)
        {
            // We have a long data validation and preparation process
            if (userSuppliedIdentifier == null)
            {
                throw new ArgumentNullException("userSuppliedIdentifier");
            }
            if (relyingParty == null)
            {
                throw new ArgumentNullException("relyingParty");
            }
            if (realm == null)
            {
                throw new ArgumentNullException("realm");
            }

            userSuppliedIdentifier = userSuppliedIdentifier.TrimFragment();
            if (relyingParty.Settings.RequireSsl)
            {
                // Rather than check for successful SSL conversion at this stage,
                // We'll wait for secure discovery to fail on the new identifier.
                userSuppliedIdentifier.TryRequireSsl(out userSuppliedIdentifier);
            }
            //Logger.InfoFormat("Creating authentication request for user supplied Identifier: {0}",
            //	userSuppliedIdentifier);
            //Logger.DebugFormat("Realm: {0}", realm);
            //Logger.DebugFormat("Return To: {0}", returnToUrl);
            //Logger.DebugFormat("RequireSsl: {0}", userSuppliedIdentifier.IsDiscoverySecureEndToEnd);



            // Throw an exception now if the realm and the return_to URLs don't match
            // as required by the provider.  We could wait for the provider to test this and
            // fail, but this will be faster and give us a better error message.
            if (!realm.Contains(returnToUrl))
            {
                throw new OpenIdException(string.Format(CultureInfo.CurrentCulture,
                                                        Strings.ReturnToNotUnderRealm, returnToUrl, realm));
            }

            // Perform discovery right now (not deferred).
            var serviceEndpoints = userSuppliedIdentifier.Discover();

            // Call another method that defers request generation.
            return(CreateInternal(userSuppliedIdentifier, relyingParty, realm, returnToUrl, serviceEndpoints, createNewAssociationsAsNeeded));
        }
コード例 #11
0
        public static CheckAuthRequest Create(OpenIdRelyingParty relyingParty, ServiceEndpoint provider, IDictionary <string, string> query)
        {
            if (relyingParty == null)
            {
                throw new ArgumentNullException("relyingParty");
            }
            Protocol protocol = provider.Protocol;
            string   signed   = query[protocol.openid.signed];

            if (signed == null)
            {
                // #XXX: oidutil.log('No signature present; checkAuth aborted')
                return(null);
            }

            // Arguments that are always passed to the server and not
            // included in the signature.
            string[] whitelist = new string[] { protocol.openidnp.assoc_handle, protocol.openidnp.sig, protocol.openidnp.signed, protocol.openidnp.invalidate_handle };
            string[] splitted  = signed.Split(',');

            // combine the previous 2 arrays (whitelist + splitted) into a new array: signed_array
            string[] signed_array = new string[whitelist.Length + splitted.Length];
            Array.Copy(whitelist, signed_array, whitelist.Length);
            Array.Copy(splitted, 0, signed_array, whitelist.Length, splitted.Length);

            var check_args = new Dictionary <string, string>();

            foreach (string key in query.Keys)
            {
                if (key.StartsWith(protocol.openid.Prefix, StringComparison.OrdinalIgnoreCase) &&
                    Array.IndexOf(signed_array, key.Substring(protocol.openid.Prefix.Length)) > -1)
                {
                    check_args[key] = query[key];
                }
            }
            check_args[protocol.openid.mode] = protocol.Args.Mode.check_authentication;

            return(new CheckAuthRequest(relyingParty, provider, check_args));
        }
コード例 #12
0
 protected DirectRequest(OpenIdRelyingParty relyingParty, ServiceEndpoint provider, IDictionary <string, string> args)
 {
     if (relyingParty == null)
     {
         throw new ArgumentNullException("relyingParty");
     }
     if (provider == null)
     {
         throw new ArgumentNullException("provider");
     }
     if (args == null)
     {
         throw new ArgumentNullException("args");
     }
     RelyingParty = relyingParty;
     Provider     = provider;
     Args         = args;
     if (Protocol.QueryDeclaredNamespaceVersion != null &&
         !Args.ContainsKey(Protocol.openid.ns))
     {
         Args.Add(Protocol.openid.ns, Protocol.QueryDeclaredNamespaceVersion);
     }
 }
コード例 #13
0
 public CheckAuthResponse(OpenIdRelyingParty relyingParty, ServiceEndpoint provider, IDictionary <string, string> args)
     : base(relyingParty, provider, args)
 {
 }
コード例 #14
0
        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);
        }
コード例 #15
0
 /// <summary>
 /// Instantiates an <see cref="AssociateRequest"/> object.
 /// </summary>
 /// <param name="relyingParty">The RP instance that is creating this request.</param>
 /// <param name="provider">The discovered OpenID Provider endpoint information.</param>
 /// <param name="args">The arguments assembled for sending to the Provider.</param>
 /// <param name="dh">Optional.  Supplied only if Diffie-Hellman is used for encrypting the association secret key.</param>
 AssociateRequest(OpenIdRelyingParty relyingParty, ServiceEndpoint provider, IDictionary <string, string> args, DiffieHellman dh)
     : base(relyingParty, provider, args)
 {
     DH = dh;
 }
コード例 #16
0
        /// <remarks>
        /// This is documented in OpenId Authentication 2.0 section 11.2.
        /// </remarks>
        static void verifyDiscoveredInfoMatchesAssertedInfo(OpenIdRelyingParty relyingParty,
                                                            IDictionary <string, string> query,
                                                            ServiceEndpoint tokenEndpoint, ServiceEndpoint responseEndpoint)
        {
            //Logger.Debug("Verifying assertion matches identifier discovery results...");

            // Verify that the actual version of the OP endpoint matches discovery.
            Protocol actualProtocol     = Protocol.Detect(query);
            Protocol discoveredProtocol = (tokenEndpoint ?? responseEndpoint).Protocol;

            if (!actualProtocol.Equals(discoveredProtocol))
            {
                // Allow an exception so that v1.1 and v1.0 can be seen as identical for this
                // verification.  v1.0 has no spec, and v1.1 and v1.0 cannot be clearly distinguished
                // from the protocol, so detecting their differences is meaningless, and throwing here
                // would just break thing unnecessarily.
                if (!(actualProtocol.Version.Major == 1 && discoveredProtocol.Version.Major == 1))
                {
                    throw new OpenIdException(string.Format(CultureInfo.CurrentCulture,
                                                            Strings.OpenIdDiscoveredAndActualVersionMismatch,
                                                            actualProtocol.Version, discoveredProtocol.Version));
                }
            }

            if ((tokenEndpoint ?? responseEndpoint).Protocol.Version.Major < 2)
            {
                Debug.Assert(tokenEndpoint != null, "Our OpenID 1.x implementation requires an RP token.  And this should have been verified by our caller.");
                // For 1.x OPs, we only need to verify that the OP Local Identifier
                // hasn't changed since we made the request.
                if (tokenEndpoint.ProviderLocalIdentifier !=
                    Util.GetRequiredArg(query, tokenEndpoint.Protocol.openid.identity))
                {
                    throw new OpenIdException(string.Format(CultureInfo.CurrentCulture,
                                                            Strings.TamperingDetected, tokenEndpoint.Protocol.openid.identity,
                                                            tokenEndpoint.ProviderLocalIdentifier,
                                                            Util.GetRequiredArg(query, tokenEndpoint.Protocol.openid.identity)));
                }
            }
            else
            {
                // In 2.0, we definitely have a responseEndpoint, but may not have a
                // tokenEndpoint. If we don't have a tokenEndpoint, or it doesn't match the assertion,
                // or if the user gave us an OP Identifier originally, then we need to perform discovery on
                // the responseEndpoint.ClaimedIdentifier to verify the OP has authority
                // to speak for it.
                if (tokenEndpoint == null ||                                                                    // no token included (unsolicited assertion)
                    tokenEndpoint != responseEndpoint ||                                                        // the OP is asserting something different than we asked for
                    tokenEndpoint.ClaimedIdentifier == tokenEndpoint.Protocol.ClaimedIdentifierForOPIdentifier) // or directed identity is in effect
                {
                    Identifier claimedIdentifier = Util.GetRequiredArg(query, responseEndpoint.Protocol.openid.claimed_id);
                    // Require SSL where appropriate.  This will filter out insecure identifiers,
                    // redirects and provider endpoints automatically.  If we find a match after all that
                    // filtering with the responseEndpoint, then the unsolicited assertion is secure.
                    if (relyingParty.Settings.RequireSsl && !claimedIdentifier.TryRequireSsl(out claimedIdentifier))
                    {
                        throw new OpenIdException(Strings.InsecureWebRequestWithSslRequired, query);
                    }
                    //Logger.InfoFormat("Provider asserted an identifier that requires (re)discovery to confirm.");
                    List <ServiceEndpoint> discoveredEndpoints = new List <ServiceEndpoint>(claimedIdentifier.Discover());
                    // Make sure the response endpoint matches one of the discovered endpoints.
                    if (!discoveredEndpoints.Contains(responseEndpoint))
                    {
                        throw new OpenIdException(string.Format(CultureInfo.CurrentCulture,
                                                                Strings.IssuedAssertionFailsIdentifierDiscovery,
                                                                responseEndpoint, Util.ToString(discoveredEndpoints)));
                    }
                }
            }
        }
コード例 #17
0
        internal static AuthenticationResponse Parse(IDictionary <string, string> query,
                                                     OpenIdRelyingParty relyingParty, Uri requestUrl, bool verifySignature)
        {
            if (query == null)
            {
                throw new ArgumentNullException("query");
            }
            if (requestUrl == null)
            {
                throw new ArgumentNullException("requestUrl");
            }

            //Logger.DebugFormat("OpenID authentication response received:{0}{1}", Environment.NewLine, Util.ToString(query));

            ServiceEndpoint tokenEndpoint = null;
            // The query parameter may be the POST query or the GET query,
            // but the token parameter will always be in the GET query because
            // it was added to the return_to parameter list.
            IDictionary <string, string> requestUrlQuery = Util.NameValueCollectionToDictionary(
                HttpUtility.ParseQueryString(requestUrl.Query));
            string token = Util.GetOptionalArg(requestUrlQuery, Token.TokenKey);

            if (token != null)
            {
                token         = FixDoublyUriDecodedToken(token);
                tokenEndpoint = Token.Deserialize(token, relyingParty.Store).Endpoint;
            }

            Protocol protocol = Protocol.Detect(query);
            string   mode     = Util.GetRequiredArg(query, protocol.openid.mode);

            if (mode.Equals(protocol.Args.Mode.cancel, StringComparison.Ordinal))
            {
                return(new AuthenticationResponse(AuthenticationStatus.Canceled, tokenEndpoint, query));
            }
            else if (mode.Equals(protocol.Args.Mode.setup_needed, StringComparison.Ordinal))
            {
                return(new AuthenticationResponse(AuthenticationStatus.SetupRequired, tokenEndpoint, query));
            }
            else if (mode.Equals(protocol.Args.Mode.error, StringComparison.Ordinal))
            {
                throw new OpenIdException(string.Format(CultureInfo.CurrentCulture,
                                                        "The provider returned an error: {0}", query[protocol.openid.error]));
            }
            else if (mode.Equals(protocol.Args.Mode.id_res, StringComparison.Ordinal))
            {
                // We allow unsolicited assertions (that won't have our own token on it)
                // only for OpenID 2.0 providers.
                ServiceEndpoint responseEndpoint = null;
                if (protocol.Version.Major < 2)
                {
                    if (tokenEndpoint == null)
                    {
                        throw new OpenIdException(string.Format(CultureInfo.CurrentCulture,
                                                                Strings.MissingInternalQueryParameter, Token.TokenKey));
                    }
                }
                else
                {
                    // 2.0 OPs provide enough information to assemble the entire endpoint info,
                    // except perhaps for the original user supplied identifier, which if available
                    // allows us to display a friendly XRI.
                    Identifier friendlyIdentifier = tokenEndpoint != null ? tokenEndpoint.UserSuppliedIdentifier : null;
                    responseEndpoint = ServiceEndpoint.ParseFromAuthResponse(query, friendlyIdentifier);
                    // If this is a solicited assertion, we'll have a token with endpoint data too,
                    // which we can use to more quickly confirm the validity of the claimed
                    // endpoint info.
                }
                // At this point, we are guaranteed to have tokenEndpoint ?? responseEndpoint
                // set to endpoint data (one or the other or both).
                // tokenEndpoint is known good data, whereas responseEndpoint must still be
                // verified.
                // For the error-handling and cancellation cases, the info does not have to
                // be verified, so we'll use whichever one is available.
                return(parseIdResResponse(query, tokenEndpoint, responseEndpoint, relyingParty, requestUrl, verifySignature));
            }
            else
            {
                throw new OpenIdException(string.Format(CultureInfo.CurrentCulture,
                                                        Strings.InvalidOpenIdQueryParameterValue,
                                                        protocol.openid.mode, mode), query);
            }
        }
コード例 #18
0
        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));
        }