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 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)); }
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>(); }
/// <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); } } }
public void Provider() { OpenIdRelyingParty rp = new OpenIdRelyingParty(null, null, null); Identifier id = TestSupport.GetMockIdentifier(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20); IAuthenticationRequest request = rp.CreateRequest(id, realm, returnTo); Assert.IsNotNull(request.Provider); }
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)); } if (Logger.IsErrorEnabled) { if (provider.Protocol.QueryDeclaredNamespaceVersion != null) { if (!Args.ContainsKey(Protocol.openidnp.ns)) { Logger.ErrorFormat("Direct response from provider lacked the {0} key.", Protocol.openid.ns); } else if (Args[Protocol.openidnp.ns] != Protocol.QueryDeclaredNamespaceVersion) { Logger.ErrorFormat("Direct response from provider for key {0} was '{1}' rather than '{2}'.", Protocol.openid.ns, Args[Protocol.openidnp.ns], Protocol.QueryDeclaredNamespaceVersion); } } } }
/// <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); } if (Logger.IsDebugEnabled) { if (Util.AreSequencesEquivalent(endpoints, endpointList)) { Logger.Debug("Filtering and sorting of endpoints did not affect the list."); } else { Logger.Debug("After filtering and sorting service endpoints, this is the new prioritized list:"); Logger.Debug(Util.ToString(filteredEndpoints, true)); } } return(endpointList); }
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; if (HmacShaAssociation.TryFindBestAssociation(provider.Protocol, relyingParty.Settings.MinimumHashBitLength, relyingParty.Settings.MaximumHashBitLength, true, 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); } }
public ActionResult Login(string openid_url) { if (Identifier.IsValid(openid_url)) { try { Identifier openId = Identifier.Parse(openid_url); OpenIdRelyingParty rp = new OpenIdRelyingParty(); IAuthenticationRequest request = rp.CreateRequest(openId, new Realm(OpenId.Realm), new Uri(OpenId.LoginUrl)); request.RedirectToProvider(); } catch (DotNetOpenId.OpenIdException exception) { ViewData["LoginErrorMessage"] = exception.Message; ModelState.AddModelError("LoginError", exception); } } else { ViewData["LoginErrorMessage"] = "The OpenID you provided is not in the correct format."; ModelState.AddModelError("LoginError", "The OpenID you provided is not in the correct format."); } // if we got here then something went wrong so we go back to the login view. return View(); }
public ActionResult Authenticate() { var openid = new OpenIdRelyingParty(); if (openid.Response == null) { // Stage 2: user submitting Identifier Identifier id; if (Identifier.TryParse(Request.Form["openid_identifier"], out id)) { openid.CreateRequest(Request.Form["openid_identifier"]).RedirectToProvider(); } else { ViewData["Message"] = "Invalid identifier"; return View("Login"); } } else { // Stage 3: OpenID Provider sending assertion response switch (openid.Response.Status) { case AuthenticationStatus.Authenticated: FormsAuthentication.RedirectFromLoginPage(openid.Response.ClaimedIdentifier, false); break; case AuthenticationStatus.Canceled: ViewData["Message"] = "Canceled at provider"; return View("Login"); case AuthenticationStatus.Failed: ViewData["Message"] = openid.Response.Exception.Message; return View("Login"); } } return new EmptyResult(); }
protected void Page_Load(object sender, EventArgs e) { OpenIdRelyingParty rp = new OpenIdRelyingParty(); if (rp.Response != null) { switch (rp.Response.Status) { case AuthenticationStatus.Authenticated: { AuthenticateUser(rp.Response); break; } case AuthenticationStatus.Canceled: { lblError.Text = "Authentication canceled."; break; } case AuthenticationStatus.Failed: { lblError.Text = "Authentication failed."; if (rp.Response.Exception != null) lblError.Text += " (" + rp.Response.Exception.Message + ")"; break; } case AuthenticationStatus.SetupRequired: { lblError.Text = "Authentication failed. (Setup required?)"; break; } } } }
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); }
protected void yahooLoginButton_Click(object sender, ImageClickEventArgs e) { OpenIdRelyingParty openid = new OpenIdRelyingParty(); var req = openid.CreateRequest("yahoo.com"); req.RedirectToProvider(); // We don't listen for the response from the provider explicitly // because the OpenIdLogin control is already doing that for us. }
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); }
/// <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); } if (Logger.IsWarnEnabled && returnToUrl.Query != null) { NameValueCollection returnToArgs = HttpUtility.ParseQueryString(returnToUrl.Query); foreach (string key in returnToArgs) { if (OpenIdRelyingParty.ShouldParameterBeStrippedFromReturnToUrl(key)) { Logger.WarnFormat("OpenId argument \"{0}\" found in return_to URL. This can corrupt an OpenID response.", key); break; } } } // 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)); }
/// <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); } }
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); } }
/// <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..."); 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))); } } } }
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); }
internal static AuthenticationRequest CreateSingle(Identifier userSuppliedIdentifier, OpenIdRelyingParty relyingParty, Realm realm, Uri returnToUrl) { // Just return the first generated request. var requests = Create(userSuppliedIdentifier, relyingParty, realm, returnToUrl, true).GetEnumerator(); if (requests.MoveNext()) { return(requests.Current); } else { throw new OpenIdException(Strings.OpenIdEndpointNotFound); } }
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; if (HmacShaAssociation.TryFindBestAssociation(provider.Protocol, relyingParty.Settings.MinimumHashBitLength, relyingParty.Settings.MaximumHashBitLength, true, 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; } }
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>(); }
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)); } if (Logger.IsErrorEnabled) { if (provider.Protocol.QueryDeclaredNamespaceVersion != null) { if (!Args.ContainsKey(Protocol.openidnp.ns)) { Logger.ErrorFormat("Direct response from provider lacked the {0} key.", Protocol.openid.ns); } else if (Args[Protocol.openidnp.ns] != Protocol.QueryDeclaredNamespaceVersion) { Logger.ErrorFormat("Direct response from provider for key {0} was '{1}' rather than '{2}'.", Protocol.openid.ns, Args[Protocol.openidnp.ns], Protocol.QueryDeclaredNamespaceVersion); } } } }
public void Login(string id) { var openid = new OpenIdRelyingParty(); Identifier identifier; if (!string.IsNullOrEmpty(id) && Identifier.TryParse(id, out identifier)) { openid.CreateRequest( identifier, new Realm(Request.Url.GetLeftPart(UriPartial.Authority) + Request.ApplicationPath), new Uri(Url.RouteUrl("Config", new { action = "Login" }, "http")) ).RedirectToProvider(); } else { throw new ArgumentException("Invalid OpenID."); } }
/// <summary> /// Chooses which provider endpoint is the best one to use. /// </summary> /// <returns>The best endpoint, or null if no acceptable endpoints were found.</returns> private static ServiceEndpoint selectEndpoint(ReadOnlyCollection <ServiceEndpoint> endpoints, OpenIdRelyingParty relyingParty) { List <ServiceEndpoint> filteredEndpoints = filterAndSortEndpoints(endpoints, relyingParty); // If there are no endpoint candidates... if (filteredEndpoints.Count == 0) { return(null); } // If we don't have an application store, we have no place to record an association to // and therefore can only take our best shot at one of the endpoints. if (relyingParty.Store == null) { Logger.Debug("No state store, so the first endpoint available is selected."); return(filteredEndpoints[0]); } // Go through each endpoint until we find one that we can successfully create // an association with. This is our only hint about whether an OP is up and running. // The idea here is that we don't want to redirect the user to a dead OP for authentication. // If the user has multiple OPs listed in his/her XRDS document, then we'll go down the list // and try each one until we find one that's good. int winningEndpointIndex = 0; foreach (ServiceEndpoint endpointCandidate in filteredEndpoints) { winningEndpointIndex++; // One weakness of this method is that an OP that's down, but with whom we already // created an association in the past will still pass this "are you alive?" test. Association association = getAssociation(relyingParty, endpointCandidate, true); if (association != null) { Logger.DebugFormat("Endpoint #{0} (1-based index) responded to an association request. Selecting that endpoint.", winningEndpointIndex); // We have a winner! return(endpointCandidate); } } // Since all OPs failed to form an association with us, just return the first endpoint // and hope for the best. Logger.Debug("All endpoints failed to respond to an association request. Selecting first endpoint to try to authenticate to."); return(endpoints[0]); }
public ActionResult Authenticate() { var openid = new OpenIdRelyingParty(); if (openid.Response == null) { try { var req = openid.CreateRequest(Request.Form["openid_identifier"]); var fields = new ClaimsRequest { Email = DemandLevel.Require, Nickname = DemandLevel.Require }; req.AddExtension(fields); req.RedirectToProvider(); } catch (ThreadAbortException) { } catch (Exception e) { ViewData["Message"] = e.Message; } return View("Login"); } switch (openid.Response.Status) { case AuthenticationStatus.Authenticated: var fields = openid.Response.GetExtension(typeof(ClaimsResponse)) as ClaimsResponse; if (fields != null) { TempData["Email"] = fields.Email; TempData["Nickname"] = fields.Nickname; } FormsAuthentication.RedirectFromLoginPage(openid.Response.ClaimedIdentifier, true); break; case AuthenticationStatus.Canceled: ViewData["Message"] = "Canceled at provider"; return View("Login"); case AuthenticationStatus.Failed: ViewData["Message"] = openid.Response.Exception.Message; return View("Login"); } // need this rather than returning an ActionResult. return null; }
OpenIdRelyingParty createRelyingParty() { OpenIdRelyingParty openid = new OpenIdRelyingParty(); int minsha, maxsha, minversion; if (int.TryParse(Request.QueryString["minsha"], out minsha)) { openid.Settings.MinimumHashBitLength = minsha; } if (int.TryParse(Request.QueryString["maxsha"], out maxsha)) { openid.Settings.MaximumHashBitLength = maxsha; } if (int.TryParse(Request.QueryString["minversion"], out minversion)) { switch (minversion) { case 1: openid.Settings.MinimumRequiredOpenIdVersion = ProtocolVersion.V10; break; case 2: openid.Settings.MinimumRequiredOpenIdVersion = ProtocolVersion.V20; break; default: throw new ArgumentOutOfRangeException("minversion"); } } return openid; }
public Address GetOpenIDAddress(Uri claimUri) { var openid = new OpenIdRelyingParty(); Address result=new Address(); if (openid.Response != null) { // Stage 2: user submitting Identifier var fetch = openid.Response.GetExtension<FetchResponse>(); if (fetch != null) { result.Email = GetFetchValue(fetch, "contact/email"); result.FirstName = GetFetchValue(fetch, "namePerson/first"); result.LastName = GetFetchValue(fetch, "namePerson/last"); result.Street1 = GetFetchValue(fetch, "contact/streetaddressLine1/home"); result.Street2 = GetFetchValue(fetch, "contact/streetaddressLine2/home"); result.City = GetFetchValue(fetch, "contact/city/home"); result.StateOrProvince = GetFetchValue(fetch, "contact/city/stateorprovince"); result.Country = GetFetchValue(fetch, "contact/country/home"); result.Zip = GetFetchValue(fetch, "contact/postalCode/home"); result.UserName = openid.Response.ClaimedIdentifier; } } else { var request=openid.CreateRequest(claimUri.AbsoluteUri); var fetch = new FetchRequest(); fetch.AddAttribute(new AttributeRequest("contact/email")); fetch.AddAttribute(new AttributeRequest("namePerson/first")); fetch.AddAttribute(new AttributeRequest("namePerson/last")); fetch.AddAttribute(new AttributeRequest("contact/streetaddressLine1/home")); fetch.AddAttribute(new AttributeRequest("contact/streetaddressLine2/home")); fetch.AddAttribute(new AttributeRequest("contact/city/home")); fetch.AddAttribute(new AttributeRequest("contact/city/stateorprovince")); fetch.AddAttribute(new AttributeRequest("contact/country/home")); fetch.AddAttribute(new AttributeRequest("contact/postalCode/home")); request.AddExtension(fetch); request.RedirectToProvider(); } return result; }
AuthenticationRequest(string token, Association assoc, 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.assoc = assoc; this.endpoint = endpoint; RelyingParty = relyingParty; Realm = realm; ReturnToUrl = returnToUrl; Mode = AuthenticationRequestMode.Setup; OutgoingExtensions = ExtensionArgumentsManager.CreateOutgoingExtensions(endpoint.Protocol); ReturnToArgs = new Dictionary<string, string>(); if (token != null) AddCallbackArguments(DotNetOpenId.RelyingParty.Token.TokenKey, token); }
public ActionResult Login() { var openid = new OpenIdRelyingParty(); if (openid.Response == null) { throw new InvalidOperationException("Not an OpenID response."); } else { switch (openid.Response.Status) { case AuthenticationStatus.Authenticated: SetOpenId(openid.Response.ClaimedIdentifier); FormsAuthentication.SetAuthCookie(openid.Response.ClaimedIdentifier, false); return Redirect("~"); default: return Redirect("~"); } } }
public ActionResult OpenIdReturn() { OpenIdRelyingParty rp = new OpenIdRelyingParty(); string error = string.Empty; if (rp.Response != null) { switch (rp.Response.Status) { case AuthenticationStatus.Authenticated: { return AuthenticateUser(rp.Response); } case AuthenticationStatus.Canceled: { error = "Authentication canceled."; break; } case AuthenticationStatus.Failed: { error = "Authentication failed."; if (rp.Response.Exception != null) error += " (" + rp.Response.Exception.Message + ")"; break; } case AuthenticationStatus.SetupRequired: { error = "Authentication failed. (Setup required?)"; break; } } } ViewData["LoginErrorMessage"] = error; return View("Login"); }
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)); }
public bool IsValidLogin(Uri serviceUri) { bool result = false; var openid = new OpenIdRelyingParty(); if (openid.Response == null) { // Stage 2: user submitting Identifier openid.CreateRequest(serviceUri.AbsoluteUri).RedirectToProvider(); } else { result = openid.Response.Status == AuthenticationStatus.Authenticated; if (result) { //synch the users } } return result; }
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); } } } } }
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); } }
/// <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); } if (Logger.IsWarnEnabled && returnToUrl.Query != null) { NameValueCollection returnToArgs = HttpUtility.ParseQueryString(returnToUrl.Query); foreach (string key in returnToArgs) { if (OpenIdRelyingParty.ShouldParameterBeStrippedFromReturnToUrl(key)) { Logger.WarnFormat("OpenId argument \"{0}\" found in return_to URL. This can corrupt an OpenID response.", key); break; } } } // 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); }
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) { 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); } }
/// <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; }
internal static AuthenticationRequest Create(Identifier userSuppliedIdentifier, OpenIdRelyingParty relyingParty, Realm realm, Uri returnToUrl) { 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); if (Logger.IsWarnEnabled && returnToUrl.Query != null) { NameValueCollection returnToArgs = HttpUtility.ParseQueryString(returnToUrl.Query); foreach (string key in returnToArgs) { if (OpenIdRelyingParty.ShouldParameterBeStrippedFromReturnToUrl(key)) { Logger.WarnFormat("OpenId argument \"{0}\" found in return_to URL. This can corrupt an OpenID response.", key); break; } } } var endpoints = new List<ServiceEndpoint>(userSuppliedIdentifier.Discover()); ServiceEndpoint endpoint = selectEndpoint(endpoints.AsReadOnly(), relyingParty); if (endpoint == null) throw new OpenIdException(Strings.OpenIdEndpointNotFound); Logger.DebugFormat("Discovered provider endpoint: {0}", endpoint); // 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)); string token = new Token(endpoint).Serialize(relyingParty.Store); // Retrieve the association, but don't create one, as a creation was already // attempted by the selectEndpoint method. Association association = relyingParty.Store != null ? getAssociation(relyingParty, endpoint, false) : null; return new AuthenticationRequest( token, association, endpoint, realm, returnToUrl, relyingParty); }
protected void PrepareAuthenticationRequest() { if (string.IsNullOrEmpty(Text)) throw new InvalidOperationException(DotNetOpenId.Strings.OpenIdTextBoxEmpty); try { var consumer = new OpenIdRelyingParty(); // Resolve the trust root, and swap out the scheme and port if necessary to match the // return_to URL, since this match is required by OpenId, and the consumer app // may be using HTTP at some times and HTTPS at others. UriBuilder realm = getResolvedRealm(RealmUrl); realm.Scheme = Page.Request.Url.Scheme; realm.Port = Page.Request.Url.Port; // Initiate openid request Request = consumer.CreateRequest(Text, new Realm(realm)); Request.Mode = ImmediateMode ? AuthenticationRequestMode.Immediate : AuthenticationRequestMode.Setup; if (EnableRequestProfile) addProfileArgs(Request); } catch (WebException ex) { OnFailed(new FailedAuthenticationResponse(ex)); } catch (OpenIdException ex) { OnFailed(new FailedAuthenticationResponse(ex)); } }
/// <summary> /// Checks for incoming OpenID authentication responses and fires appropriate events. /// </summary> protected override void OnLoad(EventArgs e) { base.OnLoad(e); var consumer = new OpenIdRelyingParty(); if (consumer.Response != null) { switch (consumer.Response.Status) { case AuthenticationStatus.Canceled: OnCanceled(consumer.Response); break; case AuthenticationStatus.Authenticated: OnLoggedIn(consumer.Response); break; case AuthenticationStatus.SetupRequired: OnSetupRequired(consumer.Response); break; case AuthenticationStatus.Failed: OnFailed(consumer.Response); break; default: throw new InvalidOperationException("Unexpected response status code."); } } }
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)); }
public CheckAuthResponse(OpenIdRelyingParty relyingParty, ServiceEndpoint provider, IDictionary <string, string> args) : base(relyingParty, provider, args) { }
public Yield UserLogin(DreamContext context, DreamMessage request, Result<DreamMessage> response) { string userSuppliedIdentifier = context.GetParam("url", null); if (String.IsNullOrEmpty(userSuppliedIdentifier)) { _log.Info("No identifier was specified"); throw new DreamBadRequestException("No identifier was specified."); } XUri returnUri = new XUri(context.GetParam("returnurl", null)); String realm = context.GetParam("realm", null); if (String.IsNullOrEmpty(realm)) { realm = returnUri.WithoutPathQueryFragment().ToString(); } IAuthenticationRequest openIdRequest; // dummy parameters required by DotNetOpenId 2.x; in 3.x, you can // just pass null to the OpenIdRelyingParty constructor. Uri identifierUri = new Uri(userSuppliedIdentifier); NameValueCollection queryCol = System.Web.HttpUtility.ParseQueryString(identifierUri.Query); OpenIdRelyingParty openid = new OpenIdRelyingParty(null, identifierUri, queryCol); // creating an OpenID request will authenticate that // the endpoint exists and is an OpenID provider. _log.DebugFormat("Creating OpenID request: identifier {0}, return URL {1}, realm {2}", userSuppliedIdentifier, returnUri.ToString(), realm); try { openIdRequest = openid.CreateRequest( userSuppliedIdentifier, realm, returnUri.ToUri()); } catch (OpenIdException ex) { _log.WarnFormat("'{0}' rejected as OpenID identifier: {1}", userSuppliedIdentifier, ex.Message); throw new DreamBadRequestException(string.Format("'{0}' is not a valid OpenID identifier. {1}", userSuppliedIdentifier, ex.Message)); } // Ask for the e-mail address on this request. // Use both SREG and AX, to increase the odds of getting it. openIdRequest.AddExtension(new ClaimsRequest{ Email = DemandLevel.Require, }); var fetch = new FetchRequest(); fetch.AddAttribute(new AttributeRequest(WellKnownAttributes.Contact.Email, true)); openIdRequest.AddExtension(fetch); // The RedirectingResponse either contains a "Location" header for // a HTTP GET, which will return in the response as 'endpoint', or // a HTML FORM which needs to be displayed to the user, which will // return in the response as 'form'. IResponse wr = openIdRequest.RedirectingResponse; XDoc result = new XDoc("openid"); if (String.IsNullOrEmpty(wr.Headers["Location"])) { System.Text.UTF8Encoding enc = new System.Text.UTF8Encoding(); string formBody = enc.GetString(wr.Body); _log.DebugFormat("OpenID redirect by HTML FORM: {0}", formBody); result.Attr("form", formBody); } else { string redirectUrl = wr.Headers["Location"]; _log.DebugFormat("OpenID redirect URL: {0}", redirectUrl); result.Attr("endpoint", redirectUrl); } response.Return(DreamMessage.Ok(result)); yield break; }
public Yield ValidateOpenIdResponse(DreamContext context, DreamMessage request, Result<DreamMessage> response) { XUri publicUri = new XUri(context.GetParam("url", null)); NameValueCollection queryColl = System.Web.HttpUtility.ParseQueryString(context.GetParam("query", null)); // process the response, including validating the endpoint of the claimed identifier. OpenIdRelyingParty openid = new OpenIdRelyingParty(null, publicUri, queryColl); var openIdResponse = openid.Response; if (openIdResponse != null) { switch (openIdResponse.Status) { case AuthenticationStatus.Authenticated: // Throw an exception if there is a regex for acceptable // identifiers defined, and the ID does not match. if (!String.IsNullOrEmpty(_validIdPattern)) { Regex identifierAccept = new Regex(_validIdPattern); if (!identifierAccept.IsMatch(openIdResponse.ClaimedIdentifier)) { _log.InfoFormat("Identifier {0} denied access by valid-id-pattern regular expression {1}", openIdResponse.ClaimedIdentifier, _validIdPattern); throw new DreamBadRequestException("This service is configured to deny access to this OpenID identifier."); } } var claimsResponse = openIdResponse.GetExtension<ClaimsResponse>(); var fetchResponse = openIdResponse.GetExtension<FetchResponse>(); XDoc result = new XDoc("openid"); result.Attr("validated", true); result.Elem("identifier", openIdResponse.ClaimedIdentifier); // SREG response if (claimsResponse != null) { string email = claimsResponse.Email; if (email != null) { result.Elem("email", email); _log.DebugFormat("E-mail address from SREG: {0}", email); } } // AX response if (fetchResponse != null) { foreach (AttributeValues v in fetchResponse.Attributes) { if (v.TypeUri == WellKnownAttributes.Contact.Email) { IList<string> emailAddresses = v.Values; string email = emailAddresses.Count > 0 ? emailAddresses[0] : null; result.Elem("email", email); _log.DebugFormat("E-mail address from AX: {0}", email); } } } response.Return(DreamMessage.Ok(result)); break; case AuthenticationStatus.Canceled: _log.InfoFormat("Authentication was cancelled by the user."); throw new DreamBadRequestException("Authentication was cancelled by the user."); case AuthenticationStatus.Failed: _log.InfoFormat("Authentication failed: " + openIdResponse.Exception.Message); throw new DreamBadRequestException("Authentication failed: " + openIdResponse.Exception.Message); default: _log.WarnFormat("Authentication error: " + openIdResponse.Exception.Message); throw new DreamBadRequestException("Authentication error: " + openIdResponse.Exception.Message); } } else { _log.Warn("OpenID response was null"); throw new DreamBadRequestException("No OpenID response was returned."); } yield break; }
/// <summary> /// Returns a filtered and sorted list of the available OP endpoints for a discovered Identifier. /// </summary> private static List<ServiceEndpoint> filterAndSortEndpoints(ReadOnlyCollection<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 hostFilter = relyingParty.EndpointFilter ?? (ep => true); var filteredEndpoints = new List<IXrdsProviderEndpoint>(endpoints.Count); foreach (ServiceEndpoint endpoint in endpoints) { if (versionFilter(endpoint) && hostFilter(endpoint)) { filteredEndpoints.Add(endpoint); } } // 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); } return endpointList; }
/// <summary> /// Chooses which provider endpoint is the best one to use. /// </summary> /// <returns>The best endpoint, or null if no acceptable endpoints were found.</returns> private static ServiceEndpoint selectEndpoint(ReadOnlyCollection<ServiceEndpoint> endpoints, OpenIdRelyingParty relyingParty) { List<ServiceEndpoint> filteredEndpoints = filterAndSortEndpoints(endpoints, relyingParty); // If there are no endpoint candidates... if (filteredEndpoints.Count == 0) { return null; } // If we don't have an application store, we have no place to record an association to // and therefore can only take our best shot at one of the endpoints. if (relyingParty.Store == null) { return filteredEndpoints[0]; } // Go through each endpoint until we find one that we can successfully create // an association with. This is our only hint about whether an OP is up and running. // The idea here is that we don't want to redirect the user to a dead OP for authentication. // If the user has multiple OPs listed in his/her XRDS document, then we'll go down the list // and try each one until we find one that's good. foreach (ServiceEndpoint endpointCandidate in filteredEndpoints) { // One weakness of this method is that an OP that's down, but with whom we already // created an association in the past will still pass this "are you alive?" test. Association association = getAssociation(relyingParty, endpointCandidate, true); if (association != null) { // We have a winner! return endpointCandidate; } } // Since all OPs failed to form an association with us, just return the first endpoint // and hope for the best. return endpoints[0]; }
static Association getAssociation(OpenIdRelyingParty relyingParty, ServiceEndpoint provider, bool createNewAssociationIfNeeded) { if (relyingParty == null) throw new ArgumentNullException("relyingParty"); if (provider == null) throw new ArgumentNullException("provider"); // 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 (assoc != null) { 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.GetRequiredArgAllowEmptyValue(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.GetRequiredArgAllowEmptyValue(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; }
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); }
public AuthenticationResult Authenticate(string userIdentifier) { var openid = new OpenIdRelyingParty(); if (openid.Response == null) { // Redirect the user to the provider party. They will login, and be redirected // back here. try { var claims = new ClaimsRequest(); claims.Nickname = DemandLevel.Require; claims.FullName = DemandLevel.Require; claims.Email = DemandLevel.Require; claims.PostalCode = DemandLevel.Request; var id = Identifier.Parse(userIdentifier); var request = openid.CreateRequest(userIdentifier); request.AddExtension(claims); request.RedirectToProvider(); } catch (OpenIdException ex) { // The user may have entered an incorrectly formatted URI, the server is offline, etc. return new AuthenticationResult() { Cancelled = false, Error = ex, Success = false, Username = userIdentifier }; } } else { // The OpenID provider has processed the user's request and redirected them back here. switch (openid.Response.Status) { case AuthenticationStatus.Authenticated: // Update the member information return new AuthenticationResult() {Cancelled = false, Error = null, Success = true, Username = userIdentifier}; case AuthenticationStatus.Canceled: return new AuthenticationResult() {Cancelled = true, Error = null, Success = false, Username = userIdentifier}; case AuthenticationStatus.Failed: return new AuthenticationResult() {Cancelled = false, Error = null, Success = false, Username = userIdentifier}; } } return null; }