private double ParameterizedCheckIdTest(Protocol protocol, string assocType) { Association assoc = HmacShaAssociation.Create( protocol, assocType, AssociationRelyingPartyType.Smart, this.provider.SecuritySettings); this.provider.AssociationStore.StoreAssociation(AssociationRelyingPartyType.Smart, assoc); var checkidRequest = this.CreateCheckIdRequest(true); Stopwatch timer = new Stopwatch(); timer.Start(); int iterations; for (iterations = 0; timer.ElapsedMilliseconds < TestRunTime.TotalMilliseconds; iterations++) { var request = (IAuthenticationRequest)this.provider.GetRequest(checkidRequest); request.IsAuthenticated = true; var response = this.provider.PrepareResponse(request); Assert.IsInstanceOf <PositiveAssertionResponse>(response.OriginalMessage); } timer.Stop(); double executionsPerSecond = GetExecutionsPerSecond(iterations, timer); TestUtilities.TestLogger.InfoFormat("Responded to {0} checkid messages in {1}; or {2} authentications per second.", iterations, timer.Elapsed, executionsPerSecond); return(executionsPerSecond); }
/// <summary> /// Creates a Provider's response to an incoming association request. /// </summary> /// <param name="requestMessage">The request message.</param> /// <param name="associationStore">The association store.</param> /// <param name="securitySettings">The security settings on the Provider.</param> /// <returns> /// The appropriate association response that is ready to be sent back to the Relying Party. /// </returns> /// <remarks> /// <para>If an association is created, it will be automatically be added to the provided /// association store.</para> /// <para>Successful association response messages will derive from <see cref="AssociateSuccessfulResponse"/>. /// Failed association response messages will derive from <see cref="AssociateUnsuccessfulResponse"/>.</para> /// </remarks> internal static IProtocolMessage CreateResponse(IAssociateRequestProvider requestMessage, IProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings) { Requires.NotNull(requestMessage, "requestMessage"); Requires.NotNull(associationStore, "associationStore"); Requires.NotNull(securitySettings, "securitySettings"); AssociateRequest request = (AssociateRequest)requestMessage; IProtocolMessage response; var protocol = requestMessage.GetProtocol(); if (securitySettings.IsAssociationInPermittedRange(protocol, request.AssociationType) && HmacShaAssociation.IsDHSessionCompatible(protocol, request.AssociationType, request.SessionType)) { response = requestMessage.CreateResponseCore(); // Create and store the association if this is a successful response. var successResponse = response as IAssociateSuccessfulResponseProvider; if (successResponse != null) { OpenIdProviderUtilities.CreateAssociation(request, successResponse, associationStore, securitySettings); } } else { response = CreateUnsuccessfulResponse(requestMessage, securitySettings); } return(response); }
/// <summary> /// Creates a response that notifies the Relying Party that the requested /// association type is not supported by this Provider, and offers /// an alternative association type, if possible. /// </summary> /// <param name="requestMessage">The request message.</param> /// <param name="securitySettings">The security settings that apply to this Provider.</param> /// <returns> /// The response to send to the Relying Party. /// </returns> private static AssociateUnsuccessfulResponse CreateUnsuccessfulResponse(IAssociateRequestProvider requestMessage, ProviderSecuritySettings securitySettings) { Requires.NotNull(requestMessage, "requestMessage"); Requires.NotNull(securitySettings, "securitySettings"); var unsuccessfulResponse = new AssociateUnsuccessfulResponse(requestMessage.Version, (AssociateRequest)requestMessage); // The strategy here is to suggest that the RP try again with the lowest // permissible security settings, giving the RP the best chance of being // able to match with a compatible request. bool unencryptedAllowed = requestMessage.Recipient.IsTransportSecure(); bool useDiffieHellman = !unencryptedAllowed; var request = (AssociateRequest)requestMessage; var protocol = requestMessage.GetProtocol(); string associationType, sessionType; if (HmacShaAssociation.TryFindBestAssociation(protocol, false, securitySettings, useDiffieHellman, out associationType, out sessionType)) { ErrorUtilities.VerifyInternal(request.AssociationType != associationType, "The RP asked for an association that should have been allowed, but the OP is trying to suggest the same one as an alternative!"); unsuccessfulResponse.AssociationType = associationType; unsuccessfulResponse.SessionType = sessionType; Logger.OpenId.InfoFormat( "Association requested of type '{0}' and session '{1}', which the Provider does not support. Sending back suggested alternative of '{0}' with session '{1}'.", request.AssociationType, request.SessionType, unsuccessfulResponse.AssociationType, unsuccessfulResponse.SessionType); } else { Logger.OpenId.InfoFormat("Association requested of type '{0}' and session '{1}', which the Provider does not support. No alternative association type qualified for suggesting back to the Relying Party.", request.AssociationType, request.SessionType); } return(unsuccessfulResponse); }
public void Sign() { Association assoc1 = HmacShaAssociation.Create(Protocol.Default, Protocol.Default.Args.SignatureAlgorithm.HMAC_SHA1, "h1", this.sha1Secret, TimeSpan.FromMinutes(2)); Association assoc2 = HmacShaAssociation.Create(Protocol.Default, Protocol.Default.Args.SignatureAlgorithm.HMAC_SHA1, "h2", this.sha1Secret2, TimeSpan.FromMinutes(2)); var data = new byte[] { 0xdd, 0xcc }; // sign once and verify that it's sane byte[] signature1 = assoc1.Sign(data); Assert.IsNotNull(signature1); Assert.AreNotEqual(0, signature1.Length); // sign again and make sure it's different byte[] signature2 = assoc2.Sign(data); Assert.IsNotNull(signature2); Assert.AreNotEqual(0, signature2.Length); Assert.IsFalse(MessagingUtilities.AreEquivalent(signature1, signature2)); // sign again with the same secret and make sure it's the same. Assert.IsTrue(MessagingUtilities.AreEquivalent(signature1, assoc1.Sign(data))); // now change the data and make sure signature changes data[1] = 0xee; Assert.IsFalse(MessagingUtilities.AreEquivalent(signature1, assoc1.Sign(data))); }
public void SignSome() { Association assoc = HmacShaAssociation.Create(Protocol.Default, Protocol.Default.Args.SignatureAlgorithm.HMAC_SHA1, "h1", sha1Secret, TimeSpan.FromMinutes(2)); const string prefix = "q."; var dict = new Dictionary <string, string>(); dict.Add("q.a", "b"); dict.Add("q.c", "d"); dict.Add("q.e", "f"); var signKeys = new List <string> { "a", "c" }; // don't sign e byte[] sig1 = assoc.Sign(dict, signKeys, prefix); // change the unsigned value and verify that the sig doesn't change dict["q.e"] = "g"; Assert.IsTrue(Util.ArrayEquals(sig1, assoc.Sign(dict, signKeys, prefix))); // change a signed value and verify that the sig does change. dict["q.c"] = "D"; Assert.IsFalse(Util.ArrayEquals(sig1, assoc.Sign(dict, signKeys, prefix))); // change the ordering of signed fields and verify that the signature changes. dict["q.c"] = "d"; // put this back first. Assert.IsTrue(Util.ArrayEquals(sig1, assoc.Sign(dict, signKeys, prefix))); signKeys.Insert(0, signKeys[1]); signKeys.RemoveAt(2); Assert.IsFalse(Util.ArrayEquals(sig1, assoc.Sign(dict, signKeys, prefix))); }
/// <summary> /// Creates a new association of a given type at an OpenID Provider. /// </summary> /// <param name="protocol">The protocol.</param> /// <param name="associationType">Type of the association (i.e. HMAC-SHA1 or HMAC-SHA256)</param> /// <param name="associationUse">A value indicating whether the new association will be used privately by the Provider for "dumb mode" authentication /// or shared with the Relying Party for "smart mode" authentication.</param> /// <param name="associationStore">The Provider's association store.</param> /// <param name="securitySettings">The security settings of the Provider.</param> /// <returns> /// The newly created association. /// </returns> /// <remarks> /// The new association is NOT automatically put into an association store. This must be done by the caller. /// </remarks> internal static HmacShaAssociation Create(Protocol protocol, string associationType, AssociationRelyingPartyType associationUse, IProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings) { Requires.NotNull(protocol, "protocol"); Requires.NotNullOrEmpty(associationType, "associationType"); Requires.NotNull(associationStore, "associationStore"); Requires.NotNull(securitySettings, "securitySettings"); int secretLength = HmacShaAssociation.GetSecretLength(protocol, associationType); // Generate the secret that will be used for signing byte[] secret = MessagingUtilities.GetCryptoRandomData(secretLength); TimeSpan lifetime; if (associationUse == AssociationRelyingPartyType.Smart) { if (!securitySettings.AssociationLifetimes.TryGetValue(associationType, out lifetime)) { lifetime = DefaultMaximumLifetime; } } else { lifetime = HmacShaAssociation.DumbSecretLifetime; } string handle = associationStore.Serialize(secret, DateTime.UtcNow + lifetime, associationUse == AssociationRelyingPartyType.Dumb); Assumes.True(protocol != null); // All the way up to the method call, the condition holds, yet we get a Requires failure next Assumes.True(secret != null); Assumes.True(!string.IsNullOrEmpty(associationType)); var result = HmacShaAssociation.Create(protocol, associationType, handle, secret, lifetime); return(result); }
/// <summary> /// Creates a Provider's response to an incoming association request. /// </summary> /// <param name="associationStore">The association store where a new association (if created) will be stored. Must not be null.</param> /// <param name="securitySettings">The security settings on the Provider.</param> /// <returns> /// The appropriate association response that is ready to be sent back to the Relying Party. /// </returns> /// <remarks> /// <para>If an association is created, it will be automatically be added to the provided /// association store.</para> /// <para>Successful association response messages will derive from <see cref="AssociateSuccessfulResponse"/>. /// Failed association response messages will derive from <see cref="AssociateUnsuccessfulResponse"/>.</para> /// </remarks> internal IProtocolMessage CreateResponse(IAssociationStore <AssociationRelyingPartyType> associationStore, ProviderSecuritySettings securitySettings) { Contract.Requires <ArgumentNullException>(associationStore != null); Contract.Requires <ArgumentNullException>(securitySettings != null); IProtocolMessage response; if (securitySettings.IsAssociationInPermittedRange(Protocol, this.AssociationType) && HmacShaAssociation.IsDHSessionCompatible(Protocol, this.AssociationType, this.SessionType)) { response = this.CreateResponseCore(); // Create and store the association if this is a successful response. var successResponse = response as AssociateSuccessfulResponse; if (successResponse != null) { Association association = successResponse.CreateAssociation(this, securitySettings); associationStore.StoreAssociation(AssociationRelyingPartyType.Smart, association); } } else { response = this.CreateUnsuccessfulResponse(securitySettings); } return(response); }
public void Sign() { Association assoc1 = HmacShaAssociation.Create(Protocol.Default, Protocol.Default.Args.SignatureAlgorithm.HMAC_SHA1, "h1", this.sha1Secret, TimeSpan.FromMinutes(2)); Association assoc2 = HmacShaAssociation.Create(Protocol.Default, Protocol.Default.Args.SignatureAlgorithm.HMAC_SHA1, "h2", this.sha1Secret2, TimeSpan.FromMinutes(2)); var data = new byte[] { 0xdd, 0xcc }; // sign once and verify that it's sane byte[] signature1 = assoc1.Sign(data); Assert.That(signature1, Is.Not.Null); Assert.That(signature1.Length, Is.Not.EqualTo(0)); // sign again and make sure it's different byte[] signature2 = assoc2.Sign(data); Assert.That(signature2, Is.Not.Null); Assert.That(signature2.Length, Is.Not.EqualTo(0)); Assert.That(signature1, Is.Not.EqualTo(signature2)); // sign again with the same secret and make sure it's the same. Assert.That(assoc1.Sign(data), Is.EqualTo(signature1)); // now change the data and make sure signature changes data[1] = 0xee; Assert.That(assoc1.Sign(data), Is.Not.EqualTo(signature1)); }
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 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); } }
/// <summary> /// Called to create the Association based on a request previously given by the Relying Party. /// </summary> /// <param name="request">The prior request for an association.</param> /// <param name="securitySettings">The security settings of the Provider.</param> /// <returns>The created association.</returns> /// <remarks> /// <para>The caller will update this message's /// <see cref="AssociateSuccessfulResponse.ExpiresIn"/> and /// <see cref="AssociateSuccessfulResponse.AssociationHandle"/> /// properties based on the <see cref="Association"/> returned by this method, but any other /// association type specific properties must be set by this method.</para> /// <para>The response message is updated to include the details of the created association by this method, /// but the resulting association is <i>not</i> added to the association store and must be done by the caller.</para> /// </remarks> protected override Association CreateAssociationAtProvider(AssociateRequest request, ProviderSecuritySettings securitySettings) { Association association = HmacShaAssociation.Create(Protocol, this.AssociationType, AssociationRelyingPartyType.Smart, securitySettings); this.MacKey = association.SecretKey; return(association); }
public void Best() { Association a = HmacShaAssociation.Create( Protocol.Default, Protocol.Default.Args.SignatureAlgorithm.HMAC_SHA1, "h1", this.sha1Secret, TimeSpan.FromHours(1)); Association b = HmacShaAssociation.Create( Protocol.Default, Protocol.Default.Args.SignatureAlgorithm.HMAC_SHA1, "h2", this.sha1Secret, TimeSpan.FromHours(1)); this.assocs.Set(a); this.assocs.Set(b); // make b the best by making a older a.Issued -= TimeSpan.FromHours(1); Assert.AreSame(b, this.assocs.Best.FirstOrDefault()); // now make a the best b.Issued -= TimeSpan.FromHours(2); Assert.AreSame(a, this.assocs.Best.FirstOrDefault()); }
/// <summary> /// Creates the association at the provider side after the association request has been received. /// </summary> /// <param name="request">The association request.</param> /// <param name="securitySettings">The security settings of the Provider.</param> /// <returns>The newly created association.</returns> /// <remarks> /// The response message is updated to include the details of the created association by this method, /// but the resulting association is <i>not</i> added to the association store and must be done by the caller. /// </remarks> protected override Association CreateAssociationAtProvider(AssociateRequest request, ProviderSecuritySettings securitySettings) { ErrorUtilities.VerifyArgumentNotNull(request, "request"); var diffieHellmanRequest = request as AssociateDiffieHellmanRequest; ErrorUtilities.VerifyArgument(diffieHellmanRequest != null, "request"); ErrorUtilities.VerifyArgumentNotNull(securitySettings, "securitySettings"); this.SessionType = this.SessionType ?? request.SessionType; // Go ahead and create the association first, complete with its secret that we're about to share. Association association = HmacShaAssociation.Create(this.Protocol, this.AssociationType, AssociationRelyingPartyType.Smart, securitySettings); this.AssociationHandle = association.Handle; this.ExpiresIn = association.SecondsTillExpiration; // We now need to securely communicate the secret to the relying party using Diffie-Hellman. // We do this by performing a DH algorithm on the secret and setting a couple of properties // that will be transmitted to the Relying Party. The RP will perform an inverse operation // using its part of a DH secret in order to decrypt the shared secret we just invented // above when we created the association. DiffieHellman dh = new DiffieHellmanManaged( diffieHellmanRequest.DiffieHellmanModulus ?? AssociateDiffieHellmanRequest.DefaultMod, diffieHellmanRequest.DiffieHellmanGen ?? AssociateDiffieHellmanRequest.DefaultGen, AssociateDiffieHellmanRequest.DefaultX); HashAlgorithm hasher = DiffieHellmanUtilities.Lookup(this.Protocol, this.SessionType); this.DiffieHellmanServerPublic = DiffieHellmanUtilities.EnsurePositive(dh.CreateKeyExchange()); this.EncodedMacKey = DiffieHellmanUtilities.SHAHashXorSecret(hasher, dh, diffieHellmanRequest.DiffieHellmanConsumerPublic, association.SecretKey); return(association); }
public async Task CreateRequest() { var rp = this.CreateRelyingParty(); StoreAssociation(rp, OPUri, HmacShaAssociation.Create("somehandle", new byte[20], TimeSpan.FromDays(1))); Identifier id = Identifier.Parse(GetMockIdentifier(ProtocolVersion.V20)); var req = await rp.CreateRequestAsync(id, RPRealmUri, RPUri); Assert.IsNotNull(req); }
public void CreateRequests() { var rp = this.CreateRelyingParty(); StoreAssociation(rp, OPUri, HmacShaAssociation.Create("somehandle", new byte[20], TimeSpan.FromDays(1))); Identifier id = Identifier.Parse(GetMockIdentifier(ProtocolVersion.V20)); var requests = rp.CreateRequests(id, RPRealmUri, RPUri); Assert.AreEqual(1, requests.Count()); }
public void HandleLifecycle() { Association a = HmacShaAssociation.Create(Protocol.Default, Protocol.Default.Args.SignatureAlgorithm.HMAC_SHA1, "somehandle", sha1Secret, TimeSpan.FromDays(1)); assocs.Set(a); Assert.AreSame(a, assocs.Get(a.Handle)); Assert.IsTrue(assocs.Remove(a.Handle)); Assert.IsNull(assocs.Get(a.Handle)); Assert.IsFalse(assocs.Remove(a.Handle)); }
public void Properties() { string handle = "somehandle"; TimeSpan lifetime = TimeSpan.FromMinutes(2); Association assoc = HmacShaAssociation.Create(Protocol.Default, Protocol.Default.Args.SignatureAlgorithm.HMAC_SHA1, handle, this.sha1Secret, lifetime); Assert.IsFalse(assoc.IsExpired); Assert.IsTrue(Math.Abs((DateTime.Now - assoc.Issued.ToLocalTime()).TotalSeconds) < deltaDateTime.TotalSeconds); Assert.IsTrue(Math.Abs((DateTime.Now.ToLocalTime() + lifetime - assoc.Expires.ToLocalTime()).TotalSeconds) < deltaDateTime.TotalSeconds); Assert.AreEqual(handle, assoc.Handle); Assert.IsTrue(Math.Abs(lifetime.TotalSeconds - assoc.SecondsTillExpiration) < deltaDateTime.TotalSeconds); Assert.IsTrue(MessagingUtilities.AreEquivalent(this.sha1Secret, assoc.SecretKey)); Assert.AreEqual(0, assoc.Issued.Millisecond, "No milliseconds because this can be cut off in conversions."); }
public void Properties() { string handle = "somehandle"; TimeSpan lifetime = TimeSpan.FromMinutes(2); Association assoc = HmacShaAssociation.Create(Protocol.Default, Protocol.Default.Args.SignatureAlgorithm.HMAC_SHA1, handle, this.sha1Secret, lifetime); Assert.IsFalse(assoc.IsExpired); Assert.That(assoc.Issued, Is.EqualTo(DateTime.UtcNow).Within(deltaDateTime)); Assert.That(assoc.Expires, Is.EqualTo(DateTime.UtcNow + lifetime).Within(deltaDateTime)); Assert.That(assoc.Handle, Is.EqualTo(handle)); Assert.That(assoc.SecondsTillExpiration, Is.EqualTo(lifetime.TotalSeconds).Within(deltaDateTime.TotalSeconds)); Assert.That(assoc.SecretKey, Is.EqualTo(this.sha1Secret)); Assert.That(assoc.Issued.Millisecond, Is.EqualTo(0), "No milliseconds because this can be cut off in conversions."); }
/// <summary> /// Creates the association at relying party side after the association response has been received. /// </summary> /// <param name="request">The original association request that was already sent and responded to.</param> /// <returns>The newly created association.</returns> /// <remarks> /// The resulting association is <i>not</i> added to the association store and must be done by the caller. /// </remarks> public Association CreateAssociationAtRelyingParty(AssociateRequest request) { var diffieHellmanRequest = request as AssociateDiffieHellmanRequest; ErrorUtilities.VerifyArgument(diffieHellmanRequest != null, OpenIdStrings.DiffieHellmanAssociationRequired); HashAlgorithm hasher = DiffieHellmanUtilities.Lookup(Protocol, this.SessionType); byte[] associationSecret = DiffieHellmanUtilities.SHAHashXorSecret(hasher, diffieHellmanRequest.Algorithm, this.DiffieHellmanServerPublic, this.EncodedMacKey); Association association = HmacShaAssociation.Create(Protocol, this.AssociationType, this.AssociationHandle, associationSecret, TimeSpan.FromSeconds(this.ExpiresIn)); return(association); }
public virtual Association CreateAssociation(AssociationRelyingPartyType associationType, OpenIdProvider provider) { if (provider == null && associationType == AssociationRelyingPartyType.Smart) { throw new ArgumentNullException("provider", "For Smart associations, the provider must be given."); } string assoc_type; Protocol associationProtocol; if (associationType == AssociationRelyingPartyType.Dumb) { // We'll just use the best association available. associationProtocol = Protocol.Default; assoc_type = associationProtocol.Args.SignatureAlgorithm.Best; } else { associationProtocol = provider.Protocol; assoc_type = Util.GetRequiredArg(provider.Query, provider.Protocol.openid.assoc_type); Debug.Assert(Array.IndexOf(provider.Protocol.Args.SignatureAlgorithm.All, assoc_type) >= 0, "This should have been checked by our caller."); } int secretLength = HmacShaAssociation.GetSecretLength(associationProtocol, assoc_type); RNGCryptoServiceProvider generator = new RNGCryptoServiceProvider(); byte[] secret = new byte[secretLength]; byte[] uniq_bytes = new byte[4]; string uniq; string handle; HmacShaAssociation assoc; generator.GetBytes(secret); generator.GetBytes(uniq_bytes); uniq = Convert.ToBase64String(uniq_bytes); double seconds = DateTime.UtcNow.Subtract(Association.UnixEpoch).TotalSeconds; handle = "{{" + assoc_type + "}{" + seconds + "}{" + uniq + "}"; TimeSpan lifeSpan = associationType == AssociationRelyingPartyType.Dumb ? dumbSecretLifetime : smartAssociationLifetime; assoc = HmacShaAssociation.Create(secretLength, handle, secret, lifeSpan); store.StoreAssociation(associationType, assoc); return(assoc); }
/// <summary> /// Gets a private Provider association used for signing messages in "dumb" mode. /// </summary> /// <returns>An existing or newly created association.</returns> private Association GetDumbAssociationForSigning() { // If no assoc_handle was given or it was invalid, the only thing // left to do is sign a message using a 'dumb' mode association. Protocol protocol = Protocol.Default; Association association = this.opAssociations.GetAssociation(AssociationRelyingPartyType.Dumb, this.opSecuritySettings); if (association == null) { association = HmacShaAssociation.Create(protocol, protocol.Args.SignatureAlgorithm.HMAC_SHA256, AssociationRelyingPartyType.Dumb, this.opSecuritySettings); this.opAssociations.StoreAssociation(AssociationRelyingPartyType.Dumb, association); } return(association); }
/// <summary> /// Simulates an extension request and response. /// </summary> /// <param name="protocol">The protocol to use in the roundtripping.</param> /// <param name="requests">The extensions to add to the request message.</param> /// <param name="responses">The extensions to add to the response message.</param> /// <remarks> /// This method relies on the extension objects' Equals methods to verify /// accurate transport. The Equals methods should be verified by separate tests. /// </remarks> internal static void Roundtrip( Protocol protocol, IEnumerable <IOpenIdMessageExtension> requests, IEnumerable <IOpenIdMessageExtension> responses) { ProviderSecuritySettings securitySettings = new ProviderSecuritySettings(); Association association = HmacShaAssociation.Create(protocol, protocol.Args.SignatureAlgorithm.Best, AssociationRelyingPartyType.Smart, securitySettings); var coordinator = new OpenIdCoordinator( rp => { RegisterExtension(rp.Channel, Mocks.MockOpenIdExtension.Factory); var requestBase = new CheckIdRequest(protocol.Version, OpenIdTestBase.OPUri, AuthenticationRequestMode.Immediate); OpenIdTestBase.StoreAssociation(rp, OpenIdTestBase.OPUri, association); requestBase.AssociationHandle = association.Handle; requestBase.ClaimedIdentifier = "http://claimedid"; requestBase.LocalIdentifier = "http://localid"; requestBase.ReturnTo = OpenIdTestBase.RPUri; foreach (IOpenIdMessageExtension extension in requests) { requestBase.Extensions.Add(extension); } rp.Channel.Send(requestBase); var response = rp.Channel.ReadFromRequest <PositiveAssertionResponse>(); var receivedResponses = response.Extensions.Cast <IOpenIdMessageExtension>(); CollectionAssert <IOpenIdMessageExtension> .AreEquivalentByEquality(responses.ToArray(), receivedResponses.ToArray()); }, op => { RegisterExtension(op.Channel, Mocks.MockOpenIdExtension.Factory); op.AssociationStore.StoreAssociation(AssociationRelyingPartyType.Smart, association); var request = op.Channel.ReadFromRequest <CheckIdRequest>(); var response = new PositiveAssertionResponse(request); var receivedRequests = request.Extensions.Cast <IOpenIdMessageExtension>(); CollectionAssert <IOpenIdMessageExtension> .AreEquivalentByEquality(requests.ToArray(), receivedRequests.ToArray()); foreach (var extensionResponse in responses) { response.Extensions.Add(extensionResponse); } op.Channel.Send(response); }); coordinator.Run(); }
public async Task CreateRequestsWithEndpointFilter() { var rp = this.CreateRelyingParty(); StoreAssociation(rp, OPUri, HmacShaAssociation.Create("somehandle", new byte[20], TimeSpan.FromDays(1))); Identifier id = Identifier.Parse(GetMockIdentifier(ProtocolVersion.V20)); rp.EndpointFilter = opendpoint => true; var requests = await rp.CreateRequestsAsync(id, RPRealmUri, RPUri); Assert.AreEqual(1, requests.Count()); rp.EndpointFilter = opendpoint => false; requests = await rp.CreateRequestsAsync(id, RPRealmUri, RPUri); Assert.AreEqual(0, requests.Count()); }
void initializeAssociation() { string assoc_type = Util.GetRequiredArg(Args, Protocol.openidnp.assoc_type); if (Array.IndexOf(Protocol.Args.SignatureAlgorithm.All, assoc_type) >= 0) { byte[] secret; string session_type; if (!Args.TryGetValue(Protocol.openidnp.session_type, out session_type) || Protocol.Args.SessionType.NoEncryption.Equals(session_type, StringComparison.Ordinal)) { secret = getDecoded(Protocol.openidnp.mac_key); } else { try { byte[] dh_server_public = getDecoded(Protocol.openidnp.dh_server_public); byte[] enc_mac_key = getDecoded(Protocol.openidnp.enc_mac_key); secret = DiffieHellmanUtil.SHAHashXorSecret(DiffieHellmanUtil.Lookup(Protocol, session_type), DH, dh_server_public, enc_mac_key); } catch (ArgumentException ex) { throw new OpenIdException(string.Format(CultureInfo.CurrentCulture, Strings.InvalidOpenIdQueryParameterValue, Protocol.openid.session_type, session_type), ex); } } string assocHandle = Util.GetRequiredArg(Args, Protocol.openidnp.assoc_handle); TimeSpan expiresIn = new TimeSpan(0, 0, Convert.ToInt32(Util.GetRequiredArg(Args, Protocol.openidnp.expires_in), CultureInfo.InvariantCulture)); try { Association = HmacShaAssociation.Create(Protocol, assoc_type, assocHandle, secret, expiresIn); } catch (ArgumentException ex) { throw new OpenIdException(string.Format(CultureInfo.CurrentCulture, Strings.InvalidOpenIdQueryParameterValue, Protocol.openid.assoc_type, assoc_type), ex); } } else { throw new OpenIdException(string.Format(CultureInfo.CurrentCulture, Strings.InvalidOpenIdQueryParameterValue, Protocol.openid.assoc_type, assoc_type)); } }
public void Sign() { Association assoc1 = HmacShaAssociation.Create(Protocol.Default, Protocol.Default.Args.SignatureAlgorithm.HMAC_SHA1, "h1", sha1Secret, TimeSpan.FromMinutes(2)); Association assoc2 = HmacShaAssociation.Create(Protocol.Default, Protocol.Default.Args.SignatureAlgorithm.HMAC_SHA1, "h2", sha1Secret2, TimeSpan.FromMinutes(2)); var dict = new Dictionary <string, string>(); dict.Add("a", "b"); dict.Add("c", "d"); var keys = new List <string>(); keys.Add("a"); keys.Add("c"); // sign once and verify that it's sane byte[] signature1 = assoc1.Sign(dict, keys); Assert.IsNotNull(signature1); Assert.AreNotEqual(0, signature1.Length); // sign again and make sure it's different byte[] signature2 = assoc2.Sign(dict, keys); Assert.IsNotNull(signature2); Assert.AreNotEqual(0, signature2.Length); Assert.IsFalse(Util.ArrayEquals(signature1, signature2)); // sign again with the same secret and make sure it's the same. Assert.IsTrue(Util.ArrayEquals(signature1, assoc1.Sign(dict, keys))); // now add data and make sure signature changes dict.Add("g", "h"); keys.Add("g"); Assert.IsFalse(Util.ArrayEquals(signature1, assoc1.Sign(dict, keys))); // now change existing data. dict.Remove("g"); keys.Remove("g"); dict["c"] = "e"; Assert.IsFalse(Util.ArrayEquals(signature1, assoc1.Sign(dict, keys))); dict.Remove("c"); keys.Remove("c"); Assert.IsFalse(Util.ArrayEquals(signature1, assoc1.Sign(dict, keys))); }
/// <summary> /// Creates an association request message that is appropriate for a given Provider. /// </summary> /// <param name="securityRequirements">The set of requirements the selected association type must comply to.</param> /// <param name="provider">The provider to create an association with.</param> /// <returns> /// The message to send to the Provider to request an association. /// Null if no association could be created that meet the security requirements /// and the provider OpenID version. /// </returns> internal static AssociateRequest Create(SecuritySettings securityRequirements, ProviderEndpointDescription provider) { ErrorUtilities.VerifyArgumentNotNull(securityRequirements, "securityRequirements"); ErrorUtilities.VerifyArgumentNotNull(provider, "provider"); // Apply our knowledge of the endpoint's transport, OpenID version, and // security requirements to decide the best association. bool unencryptedAllowed = provider.Endpoint.IsTransportSecure(); bool useDiffieHellman = !unencryptedAllowed; string associationType, sessionType; if (!HmacShaAssociation.TryFindBestAssociation(Protocol.Lookup(provider.ProtocolVersion), true, securityRequirements, useDiffieHellman, out associationType, out sessionType)) { // 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); } return(Create(securityRequirements, provider, associationType, sessionType)); }
/// <summary> /// Creates an association request message that is appropriate for a given Provider. /// </summary> /// <param name="securityRequirements">The set of requirements the selected association type must comply to.</param> /// <param name="provider">The provider to create an association with.</param> /// <returns> /// The message to send to the Provider to request an association. /// Null if no association could be created that meet the security requirements /// and the provider OpenID version. /// </returns> internal static AssociateRequest Create(SecuritySettings securityRequirements, IProviderEndpoint provider) { Contract.Requires <ArgumentNullException>(securityRequirements != null); Contract.Requires <ArgumentNullException>(provider != null); // Apply our knowledge of the endpoint's transport, OpenID version, and // security requirements to decide the best association. bool unencryptedAllowed = provider.Uri.IsTransportSecure(); bool useDiffieHellman = !unencryptedAllowed; string associationType, sessionType; if (!HmacShaAssociation.TryFindBestAssociation(Protocol.Lookup(provider.Version), true, securityRequirements, useDiffieHellman, out associationType, out sessionType)) { // There are no associations that meet all requirements. Logger.OpenId.Warn("Security requirements and protocol combination knock out all possible association types. Dumb mode forced."); return(null); } return(Create(securityRequirements, provider, associationType, sessionType)); }
/// <summary> /// Gets an association to use for signing new data. /// </summary> /// <returns> /// The association, which may have previously existed or /// may have been created as a result of this call. /// </returns> private Association GetAssociation() { Association privateAssociation = this.store.GetAssociation(SecretUri, this.securitySettings); if (privateAssociation == null || !privateAssociation.HasUsefulLifeRemaining) { int secretLength = HmacShaAssociation.GetSecretLength(Protocol.Default, Protocol.Default.Args.SignatureAlgorithm.Best); byte[] secret = MessagingUtilities.GetCryptoRandomData(secretLength); privateAssociation = HmacShaAssociation.Create(this.CreateNewAssociationHandle(), secret, this.securitySettings.PrivateSecretMaximumAge); if (!privateAssociation.HasUsefulLifeRemaining) { Logger.WarnFormat( "Brand new private association has a shorter lifespan ({0}) than the maximum allowed authentication time for a user ({1}). This may lead to login failures.", this.securitySettings.PrivateSecretMaximumAge, DotNetOpenAuthSection.Configuration.OpenId.MaxAuthenticationTime); } this.store.StoreAssociation(SecretUri, privateAssociation); } return(privateAssociation); }
public void SignaturesMatchKnownGood() { Protocol protocol = Protocol.V20; var settings = new ProviderSecuritySettings(); var store = new AssociationMemoryStore <AssociationRelyingPartyType>(); byte[] associationSecret = Convert.FromBase64String("rsSwv1zPWfjPRQU80hciu8FPDC+GONAMJQ/AvSo1a2M="); Association association = HmacShaAssociation.Create("mock", associationSecret, TimeSpan.FromDays(1)); store.StoreAssociation(AssociationRelyingPartyType.Smart, association); SigningBindingElement signer = new SigningBindingElement(store, settings); signer.Channel = new TestChannel(this.MessageDescriptions); IndirectSignedResponse message = new IndirectSignedResponse(protocol.Version, new Uri("http://rp")); ITamperResistantOpenIdMessage signedMessage = message; message.ProviderEndpoint = new Uri("http://provider"); signedMessage.UtcCreationDate = DateTime.Parse("1/1/2009"); signedMessage.AssociationHandle = association.Handle; Assert.IsNotNull(signer.ProcessOutgoingMessage(message)); Assert.AreEqual("o9+uN7qTaUS9v0otbHTuNAtbkpBm14+es9QnNo6IHD4=", signedMessage.Signature); }
/// <summary> /// Creates a new association with a given Provider. /// </summary> /// <param name="provider">The provider to create an association with.</param> /// <param name="associateRequest">The associate request. May be <c>null</c>, which will always result in a <c>null</c> return value..</param> /// <param name="retriesRemaining">The number of times to try the associate request again if the Provider suggests it.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns> /// The newly created association, or null if no association can be created with /// the given Provider given the current security settings. /// </returns> /// <exception cref="ProtocolException">Create if an error occurs while creating the new association.</exception> private async Task <Association> CreateNewAssociationAsync(IProviderEndpoint provider, AssociateRequest associateRequest, int retriesRemaining, CancellationToken cancellationToken) { Requires.NotNull(provider, "provider"); if (associateRequest == null || retriesRemaining < 0) { // this can happen if security requirements and protocol conflict // to where there are no association types to choose from. return(null); } Exception exception = null; try { var associateResponse = await this.channel.RequestAsync(associateRequest, cancellationToken); var associateSuccessfulResponse = associateResponse as IAssociateSuccessfulResponseRelyingParty; var associateUnsuccessfulResponse = associateResponse as AssociateUnsuccessfulResponse; if (associateSuccessfulResponse != null) { Association association = associateSuccessfulResponse.CreateAssociationAtRelyingParty(associateRequest); this.associationStore.StoreAssociation(provider.Uri, association); return(association); } else if (associateUnsuccessfulResponse != null) { if (string.IsNullOrEmpty(associateUnsuccessfulResponse.AssociationType)) { Logger.OpenId.Debug("Provider rejected an association request and gave no suggestion as to an alternative association type. Giving up."); return(null); } if (!this.securitySettings.IsAssociationInPermittedRange(Protocol.Lookup(provider.Version), associateUnsuccessfulResponse.AssociationType)) { Logger.OpenId.DebugFormat("Provider rejected an association request and suggested '{0}' as an association to try, which this Relying Party does not support. Giving up.", associateUnsuccessfulResponse.AssociationType); return(null); } if (retriesRemaining <= 0) { Logger.OpenId.Debug("Unable to agree on an association type with the Provider in the allowed number of retries. Giving up."); return(null); } // Make sure the Provider isn't suggesting an incompatible pair of association/session types. Protocol protocol = Protocol.Lookup(provider.Version); ErrorUtilities.VerifyProtocol( HmacShaAssociation.IsDHSessionCompatible(protocol, associateUnsuccessfulResponse.AssociationType, associateUnsuccessfulResponse.SessionType), OpenIdStrings.IncompatibleAssociationAndSessionTypes, associateUnsuccessfulResponse.AssociationType, associateUnsuccessfulResponse.SessionType); associateRequest = AssociateRequestRelyingParty.Create(this.securitySettings, provider, associateUnsuccessfulResponse.AssociationType, associateUnsuccessfulResponse.SessionType); return(await this.CreateNewAssociationAsync(provider, associateRequest, retriesRemaining - 1, cancellationToken)); } else { throw new ProtocolException(MessagingStrings.UnexpectedMessageReceivedOfMany); } } catch (ProtocolException ex) { exception = ex; } Assumes.NotNull(exception); // If the association failed because the remote server can't handle Expect: 100 Continue headers, // then our web request handler should have already accomodated for future calls. Go ahead and // immediately make one of those future calls now to try to get the association to succeed. if (UntrustedWebRequestHandler.IsExceptionFrom417ExpectationFailed(exception)) { return(await this.CreateNewAssociationAsync(provider, associateRequest, retriesRemaining - 1, cancellationToken)); } // Since having associations with OPs is not totally critical, we'll log and eat // the exception so that auth may continue in dumb mode. Logger.OpenId.ErrorFormat("An error occurred while trying to create an association with {0}. {1}", provider.Uri, exception); return(null); }