/// <summary> /// Authenicates a user based on the information in the HTTP request. /// </summary> /// <returns></returns> public override void Authenticate(AuthenticationRequest request, AuthenticationResponse response) { // Only execute the authentication if the user is not known yet if (response.Principal == null) { // Get OpenID provider's response from the http context using (var openid = new OpenIdRelyingParty()) { var openIDResponse = openid.GetResponse(); // TODO: figure out which OpenID provider sent the response // and associate with the right authenticator if (response != null) { switch (openIDResponse.Status) { case AuthenticationStatus.Authenticated: response.SetPrincipal(CreatePrincipal(openIDResponse)); break; case AuthenticationStatus.Canceled: case AuthenticationStatus.Failed: throw new System.Security.Authentication.AuthenticationException("OpenID authentication failed.", openIDResponse.Exception); // TODO case AuthenticationStatus.ExtensionsOnly: case AuthenticationStatus.SetupRequired: throw new InvalidOperationException(); default: throw new NotImplementedException(); } } } } }
public override void SetUp() { base.SetUp(); var rp = CreateRelyingParty(true); Identifier identifier = this.GetMockIdentifier(ProtocolVersion.V20); this.authReq = (AuthenticationRequest)rp.CreateRequest(identifier, RPRealmUri, RPUri); this.sreg = new ClaimsRequest { Nickname = DemandLevel.Request, FullName = DemandLevel.Request, BirthDate = DemandLevel.Request, Email = DemandLevel.Require, Country = DemandLevel.Request, PostalCode = DemandLevel.Request, Gender = DemandLevel.Request, Language = DemandLevel.Request, TimeZone = DemandLevel.Request, }; }
/// <summary> /// Performs deferred request generation for the <see cref="Create"/> method. /// </summary> /// <param name="userSuppliedIdentifier">The user supplied identifier.</param> /// <param name="relyingParty">The relying party.</param> /// <param name="realm">The realm.</param> /// <param name="returnToUrl">The return_to base URL.</param> /// <param name="serviceEndpoints">The discovered service endpoints on the Claimed Identifier.</param> /// <param name="createNewAssociationsAsNeeded">if set to <c>true</c>, associations that do not exist between this Relying Party and the asserting Providers are created before the authentication request is created.</param> /// <returns> /// A sequence of authentication requests, any of which constitutes a valid identity assertion on the Claimed Identifier. /// Never null, but may be empty. /// </returns> /// <remarks> /// All data validation and cleansing steps must have ALREADY taken place /// before calling this method. /// </remarks> private static IEnumerable<AuthenticationRequest> CreateInternal(Identifier userSuppliedIdentifier, OpenIdRelyingParty relyingParty, Realm realm, Uri returnToUrl, IEnumerable<IdentifierDiscoveryResult> serviceEndpoints, bool createNewAssociationsAsNeeded) { // DO NOT USE CODE CONTRACTS IN THIS METHOD, since it uses yield return ErrorUtilities.VerifyArgumentNotNull(userSuppliedIdentifier, "userSuppliedIdentifier"); ErrorUtilities.VerifyArgumentNotNull(relyingParty, "relyingParty"); ErrorUtilities.VerifyArgumentNotNull(realm, "realm"); ErrorUtilities.VerifyArgumentNotNull(serviceEndpoints, "serviceEndpoints"); ////Contract.Ensures(Contract.Result<IEnumerable<AuthenticationRequest>>() != null); // If shared associations are required, then we had better have an association store. ErrorUtilities.VerifyOperation(!relyingParty.SecuritySettings.RequireAssociation || relyingParty.AssociationManager.HasAssociationStore, OpenIdStrings.AssociationStoreRequired); Logger.Yadis.InfoFormat("Performing discovery on user-supplied identifier: {0}", userSuppliedIdentifier); IEnumerable<IdentifierDiscoveryResult> 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<IdentifierDiscoveryResult>(0); foreach (var endpoint in endpoints) { Logger.OpenId.DebugFormat("Creating authentication request for user supplied Identifier: {0}", userSuppliedIdentifier); // The strategy here is to prefer endpoints with whom we can create associations. Association association = null; if (relyingParty.AssociationManager.HasAssociationStore) { // 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 = createNewAssociationsAsNeeded ? relyingParty.AssociationManager.GetOrCreateAssociation(endpoint) : relyingParty.AssociationManager.GetExistingAssociation(endpoint); if (association == null && createNewAssociationsAsNeeded) { Logger.OpenId.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 -- // unless associations are set as required in our security settings. if (failedAssociationEndpoints.Count > 0) { if (relyingParty.SecuritySettings.RequireAssociation) { Logger.OpenId.Warn("Associations could not be formed with some Providers. Security settings require shared associations for authentication requests so these will be skipped."); } else { Logger.OpenId.Debug("Now generating requests for Provider endpoints that failed initial association attempts."); foreach (var endpoint in failedAssociationEndpoints) { Logger.OpenId.DebugFormat("Creating authentication request for user supplied Identifier: {0} at endpoint: {1}", userSuppliedIdentifier, endpoint.ProviderEndpoint.AbsoluteUri); // 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; } } } }
/// <summary> /// Performs deferred request generation for the <see cref="CreateAsync" /> method. /// </summary> /// <param name="userSuppliedIdentifier">The user supplied identifier.</param> /// <param name="relyingParty">The relying party.</param> /// <param name="realm">The realm.</param> /// <param name="returnToUrl">The return_to base URL.</param> /// <param name="serviceEndpoints">The discovered service endpoints on the Claimed Identifier.</param> /// <param name="createNewAssociationsAsNeeded">if set to <c>true</c>, associations that do not exist between this Relying Party and the asserting Providers are created before the authentication request is created.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns> /// A sequence of authentication requests, any of which constitutes a valid identity assertion on the Claimed Identifier. /// Never null, but may be empty. /// </returns> /// <remarks> /// All data validation and cleansing steps must have ALREADY taken place /// before calling this method. /// </remarks> private static async Task <IEnumerable <AuthenticationRequest> > CreateInternalAsync(Identifier userSuppliedIdentifier, OpenIdRelyingParty relyingParty, Realm realm, Uri returnToUrl, IEnumerable <IdentifierDiscoveryResult> serviceEndpoints, bool createNewAssociationsAsNeeded, CancellationToken cancellationToken) { Requires.NotNull(userSuppliedIdentifier, "userSuppliedIdentifier"); Requires.NotNull(relyingParty, "relyingParty"); Requires.NotNull(realm, "realm"); Requires.NotNull(serviceEndpoints, "serviceEndpoints"); //// // If shared associations are required, then we had better have an association store. ErrorUtilities.VerifyOperation(!relyingParty.SecuritySettings.RequireAssociation || relyingParty.AssociationManager.HasAssociationStore, OpenIdStrings.AssociationStoreRequired); Logger.Yadis.InfoFormat("Performing discovery on user-supplied identifier: {0}", userSuppliedIdentifier); IEnumerable <IdentifierDiscoveryResult> endpoints = FilterAndSortEndpoints(serviceEndpoints, relyingParty); var authRequestResults = endpoints.Select(async endpoint => { Logger.OpenId.DebugFormat("Creating authentication request for user supplied Identifier: {0}", userSuppliedIdentifier); // The strategy here is to prefer endpoints with whom we can create associations. if (relyingParty.AssociationManager.HasAssociationStore) { // 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 association = createNewAssociationsAsNeeded ? await relyingParty.AssociationManager.GetOrCreateAssociationAsync(endpoint, cancellationToken) : relyingParty.AssociationManager.GetExistingAssociation(endpoint); if (association == null && createNewAssociationsAsNeeded) { Logger.OpenId.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. return(new KeyValuePair <IdentifierDiscoveryResult, AuthenticationRequest>(endpoint, null)); } } return(new KeyValuePair <IdentifierDiscoveryResult, AuthenticationRequest>(endpoint, new AuthenticationRequest(endpoint, realm, returnToUrl, relyingParty))); }).ToList(); await Task.WhenAll(authRequestResults); var results = (from pair in authRequestResults where pair.Result.Value != null select pair.Result.Value).ToList(); // 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 = (from pair in authRequestResults where pair.Result.Value == null select pair.Result.Key).ToList(); // 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 -- // unless associations are set as required in our security settings. if (failedAssociationEndpoints.Count > 0) { if (relyingParty.SecuritySettings.RequireAssociation) { Logger.OpenId.Warn("Associations could not be formed with some Providers. Security settings require shared associations for authentication requests so these will be skipped."); } else { Logger.OpenId.Debug("Now generating requests for Provider endpoints that failed initial association attempts."); foreach (var endpoint in failedAssociationEndpoints) { Logger.OpenId.DebugFormat("Creating authentication request for user supplied Identifier: {0} at endpoint: {1}", userSuppliedIdentifier, endpoint.ProviderEndpoint.AbsoluteUri); // 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; results.Add(authRequest); } } } return(results); }
/// <summary> /// Performs deferred request generation for the <see cref="Create"/> method. /// </summary> /// <param name="userSuppliedIdentifier">The user supplied identifier.</param> /// <param name="relyingParty">The relying party.</param> /// <param name="realm">The realm.</param> /// <param name="returnToUrl">The return_to base URL.</param> /// <param name="serviceEndpoints">The discovered service endpoints on the Claimed Identifier.</param> /// <param name="createNewAssociationsAsNeeded">if set to <c>true</c>, associations that do not exist between this Relying Party and the asserting Providers are created before the authentication request is created.</param> /// <returns> /// A sequence of authentication requests, any of which constitutes a valid identity assertion on the Claimed Identifier. /// </returns> /// <remarks> /// All data validation and cleansing steps must have ALREADY taken place /// before calling this method. /// </remarks> private static IEnumerable<AuthenticationRequest> CreateInternal(Identifier userSuppliedIdentifier, OpenIdRelyingParty relyingParty, Realm realm, Uri returnToUrl, IEnumerable<ServiceEndpoint> serviceEndpoints, bool createNewAssociationsAsNeeded) { Logger.Yadis.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.OpenId.InfoFormat("Creating authentication request for user supplied Identifier: {0}", userSuppliedIdentifier); // The strategy here is to prefer endpoints with whom we can create associations. Association association = null; if (relyingParty.AssociationManager.HasAssociationStore) { // 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 = createNewAssociationsAsNeeded ? relyingParty.AssociationManager.GetOrCreateAssociation(endpoint.ProviderDescription) : relyingParty.AssociationManager.GetExistingAssociation(endpoint.ProviderDescription); if (association == null && createNewAssociationsAsNeeded) { Logger.OpenId.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.OpenId.WarnFormat("Now generating requests for Provider endpoints that failed initial association attempts."); foreach (var endpoint in failedAssociationEndpoints) { Logger.OpenId.WarnFormat("Creating authentication request for user supplied Identifier: {0}", userSuppliedIdentifier); // 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; } } }