diff --git a/src/.nuget/NuGet.Config b/src/.nuget/NuGet.Config new file mode 100644 index 0000000..6a318ad --- /dev/null +++ b/src/.nuget/NuGet.Config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/.nuget/NuGet.exe b/src/.nuget/NuGet.exe new file mode 100644 index 0000000..9f8781d Binary files /dev/null and b/src/.nuget/NuGet.exe differ diff --git a/src/.nuget/NuGet.targets b/src/.nuget/NuGet.targets new file mode 100644 index 0000000..3f8c37b --- /dev/null +++ b/src/.nuget/NuGet.targets @@ -0,0 +1,144 @@ + + + + $(MSBuildProjectDirectory)\..\ + + + false + + + false + + + true + + + false + + + + + + + + + + + $([System.IO.Path]::Combine($(SolutionDir), ".nuget")) + + + + + $(SolutionDir).nuget + + + + $(MSBuildProjectDirectory)\packages.$(MSBuildProjectName.Replace(' ', '_')).config + $(MSBuildProjectDirectory)\packages.$(MSBuildProjectName).config + + + + $(MSBuildProjectDirectory)\packages.config + $(PackagesProjectConfig) + + + + + $(NuGetToolsPath)\NuGet.exe + @(PackageSource) + + "$(NuGetExePath)" + mono --runtime=v4.0.30319 "$(NuGetExePath)" + + $(TargetDir.Trim('\\')) + + -RequireConsent + -NonInteractive + + "$(SolutionDir) " + "$(SolutionDir)" + + + $(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir) + $(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols + + + + RestorePackages; + $(BuildDependsOn); + + + + + $(BuildDependsOn); + BuildPackage; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Owin.Security.Saml/Owin.Security.Saml.csproj b/src/Owin.Security.Saml/Owin.Security.Saml.csproj index 43ffb32..e429e8f 100644 --- a/src/Owin.Security.Saml/Owin.Security.Saml.csproj +++ b/src/Owin.Security.Saml/Owin.Security.Saml.csproj @@ -1,92 +1,101 @@ - - - - - Debug - AnyCPU - {0054DAFD-1A69-4807-B24E-A6A6B71927C7} - Library - Properties - Owin.Security.Saml - Owin.Security.Saml - v4.5 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\packages\Microsoft.IdentityModel.Protocol.Extensions.1.0.1\lib\net45\Microsoft.IdentityModel.Protocol.Extensions.dll - - - ..\packages\Microsoft.Owin.3.0.0\lib\net45\Microsoft.Owin.dll - - - ..\packages\Microsoft.Owin.Security.3.0.0\lib\net45\Microsoft.Owin.Security.dll - - - ..\packages\Owin.1.0\lib\net40\Owin.dll - - - - - ..\packages\System.IdentityModel.Tokens.Jwt.4.0.1\lib\net45\System.IdentityModel.Tokens.Jwt.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {75e5bad2-a20c-43cc-b5c8-38004cedbdfd} - SAML2.Core - - - + + + + + Debug + AnyCPU + {0054DAFD-1A69-4807-B24E-A6A6B71927C7} + Library + Properties + Owin.Security.Saml + Owin.Security.Saml + v4.5 + 512 + ..\ + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Microsoft.IdentityModel.Protocol.Extensions.1.0.1\lib\net45\Microsoft.IdentityModel.Protocol.Extensions.dll + + + ..\packages\Microsoft.Owin.3.0.0\lib\net45\Microsoft.Owin.dll + + + ..\packages\Microsoft.Owin.Security.3.0.0\lib\net45\Microsoft.Owin.Security.dll + + + ..\packages\Owin.1.0\lib\net40\Owin.dll + + + + + ..\packages\System.IdentityModel.Tokens.Jwt.4.0.1\lib\net45\System.IdentityModel.Tokens.Jwt.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {75e5bad2-a20c-43cc-b5c8-38004cedbdfd} + SAML2.Core + + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + --> \ No newline at end of file diff --git a/src/Owin.Security.Saml/SamlMessage.cs b/src/Owin.Security.Saml/SamlMessage.cs index e353a6a..118b66d 100644 --- a/src/Owin.Security.Saml/SamlMessage.cs +++ b/src/Owin.Security.Saml/SamlMessage.cs @@ -159,10 +159,10 @@ private string AuthnRequestForIdp(IdentityProvider identityProvider, Saml20Authn context.Authentication.AuthenticationResponseChallenge.Properties.Dictionary != null && context.Authentication.AuthenticationResponseChallenge.Properties.Dictionary.Count > 0) redirectBuilder.RelayState = context.Authentication.AuthenticationResponseChallenge.Properties.Dictionary.ToDelimitedString(); - logger.DebugFormat(TraceMessages.AuthnRequestSent, redirectBuilder.Request); - - var redirectLocation = request.Destination + "?" + redirectBuilder.ToQuery(); - return redirectLocation; + logger.DebugFormat(TraceMessages.AuthnRequestSent, redirectBuilder.Request); + + var redirectLocation = string.Format( "{0}{1}{2}", request.Destination, ( request.Destination.EndsWith( "?" ) ? "&" : "?" ), redirectBuilder.ToQuery() ); + return redirectLocation; case BindingType.Post: throw new NotImplementedException(); //logger.DebugFormat(TraceMessages.AuthnRequestPrepared, identityProvider.Id, Saml20Constants.ProtocolBindings.HttpPost); @@ -201,7 +201,6 @@ private string AuthnRequestForIdp(IdentityProvider identityProvider, Saml20Authn logger.Error(SAML2.ErrorMessages.EndpointBindingInvalid); throw new Saml20Exception(SAML2.ErrorMessages.EndpointBindingInvalid); } - throw new NotImplementedException(); } private static NameValueCollection BuildParams(IReadableStringCollection query) diff --git a/src/SAML2.AspNet/Protocol/Saml20LogoutHandler.cs b/src/SAML2.AspNet/Protocol/Saml20LogoutHandler.cs index 80bb0eb..1a409e2 100644 --- a/src/SAML2.AspNet/Protocol/Saml20LogoutHandler.cs +++ b/src/SAML2.AspNet/Protocol/Saml20LogoutHandler.cs @@ -328,7 +328,7 @@ private void HandleRequest(HttpContext context) Logger.DebugFormat(TraceMessages.LogoutResponseSent, builder.Response); - context.Response.Redirect(destination.Url + "?" + builder.ToQuery(), true); + context.Response.Redirect(string.Format( "{0}{1}{2}", destination.Url, destination.Url.EndsWith("?") ? "&" : "?" , builder.ToQuery()), true); return; } diff --git a/src/SAML2.AspNet/Protocol/Saml20SignonHandler.cs b/src/SAML2.AspNet/Protocol/Saml20SignonHandler.cs index 1de5334..f410916 100644 --- a/src/SAML2.AspNet/Protocol/Saml20SignonHandler.cs +++ b/src/SAML2.AspNet/Protocol/Saml20SignonHandler.cs @@ -189,7 +189,7 @@ private void TransferClient(IdentityProvider identityProvider, Saml20AuthnReques Logger.DebugFormat(TraceMessages.AuthnRequestSent, redirectBuilder.Request); - var redirectLocation = request.Destination + "?" + redirectBuilder.ToQuery(); + var redirectLocation = string.Format( "{0}{1}{2}", request.Destination, ( request.Destination.EndsWith( "?" ) ? "&" : "?" ), redirectBuilder.ToQuery() ); context.Response.Redirect(redirectLocation, true); break; case BindingType.Post: diff --git a/src/SAML2.AspNet/SAML2.AspNet.csproj b/src/SAML2.AspNet/SAML2.AspNet.csproj index 04eb9c7..2bf9908 100644 --- a/src/SAML2.AspNet/SAML2.AspNet.csproj +++ b/src/SAML2.AspNet/SAML2.AspNet.csproj @@ -1,119 +1,116 @@ - - - - - Debug - AnyCPU - {D2136BFD-D2DA-4105-920B-8E05C090C597} - Library - Properties - SAML2.AspNet - SAML2.AspNet - v4.5 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - aspxcodebehind - - - aspxcodebehind - - - aspxcodebehind - - - - - - - - - - - - - {75e5bad2-a20c-43cc-b5c8-38004cedbdfd} - SAML2.Core - - - - - - + + + + + Debug + AnyCPU + {D2136BFD-D2DA-4105-920B-8E05C090C597} + Library + Properties + SAML2.AspNet + SAML2.AspNet + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + aspxcodebehind + + + aspxcodebehind + + + aspxcodebehind + + + + + + + + + + + + + {75e5bad2-a20c-43cc-b5c8-38004cedbdfd} + SAML2.Core + + + + --> \ No newline at end of file diff --git a/src/SAML2.Core/Bindings/HttpArtifactBindingBuilder.cs b/src/SAML2.Core/Bindings/HttpArtifactBindingBuilder.cs index 4e9ce13..a412236 100644 --- a/src/SAML2.Core/Bindings/HttpArtifactBindingBuilder.cs +++ b/src/SAML2.Core/Bindings/HttpArtifactBindingBuilder.cs @@ -14,17 +14,16 @@ public class HttpArtifactBindingBuilder : HttpSoapBindingBuilder { private readonly Saml2Configuration config; private readonly Action redirect; - private readonly Action sendResponseMessage; - - - - /// - /// Initializes a new instance of the class. - /// - /// The current http context. - /// Action to perform when redirecting. Parameter will be destination URL - /// Action to send messages to response stream - public HttpArtifactBindingBuilder(Saml2Configuration config, Action redirect, Action sendResponseMessage) + private readonly Action sendResponseMessage; + + + /// + /// Initializes a new instance of the class. + /// + /// + /// Action to perform when redirecting. Parameter will be destination URL + /// Action to send messages to response stream + public HttpArtifactBindingBuilder(Saml2Configuration config, Action redirect, Action sendResponseMessage) { if (config == null) throw new ArgumentNullException("config"); if (redirect == null) throw new ArgumentNullException("redirect"); @@ -32,59 +31,63 @@ public HttpArtifactBindingBuilder(Saml2Configuration config, Action redi this.redirect = redirect; this.config = config; this.sendResponseMessage = sendResponseMessage; - } - - /// - /// Creates an artifact and redirects the user to the IdP - /// - /// The destination of the request. - /// The authentication request. - /// Relay state from client. May be null - public void RedirectFromLogin(IdentityProviderEndpoint destination, Saml20AuthnRequest request, string relayState, Action cacheInsert) + } + + /// + /// Creates an artifact and redirects the user to the IdP + /// + /// The destination of the request. + /// The authentication request. + /// Relay state from client. May be null + /// + public void RedirectFromLogin(IdentityProviderEndpoint destination, Saml20AuthnRequest request, string relayState, Action cacheInsert) { var index = (short)config.ServiceProvider.Endpoints.DefaultSignOnEndpoint.Index; var doc = request.GetXml(); XmlSignatureUtils.SignDocument(doc, request.Request.Id, config.ServiceProvider.SigningCertificate); ArtifactRedirect(destination, index, doc, relayState, cacheInsert); - } - - - /// - /// Creates an artifact for the LogoutRequest and redirects the user to the IdP. - /// - /// The destination of the request. - /// The logout request. - /// The query string relay state value (relayState) to add to the communication - public void RedirectFromLogout(IdentityProviderEndpoint destination, Saml20LogoutRequest request, string relayState, Action cacheInsert) + } + + + /// + /// Creates an artifact for the LogoutRequest and redirects the user to the IdP. + /// + /// The destination of the request. + /// The logout request. + /// The query string relay state value (relayState) to add to the communication + /// + public void RedirectFromLogout(IdentityProviderEndpoint destination, Saml20LogoutRequest request, string relayState, Action cacheInsert) { var index = (short)config.ServiceProvider.Endpoints.DefaultLogoutEndpoint.Index; var doc = request.GetXml(); XmlSignatureUtils.SignDocument(doc, request.Request.Id, config.ServiceProvider.SigningCertificate); ArtifactRedirect(destination, index, doc, relayState, cacheInsert); - } - - /// - /// Creates an artifact for the LogoutResponse and redirects the user to the IdP. - /// - /// The destination of the response. - /// The logout response. - /// The query string relay state value to add to the communication - - public void RedirectFromLogout(IdentityProviderEndpoint destination, Saml20LogoutResponse response, string relayState, Action cacheInsert) + } + + /// + /// Creates an artifact for the LogoutResponse and redirects the user to the IdP. + /// + /// The destination of the response. + /// The logout response. + /// The query string relay state value to add to the communication + /// + public void RedirectFromLogout(IdentityProviderEndpoint destination, Saml20LogoutResponse response, string relayState, Action cacheInsert) { var index = (short)config.ServiceProvider.Endpoints.DefaultLogoutEndpoint.Index; var doc = response.GetXml(); XmlSignatureUtils.SignDocument(doc, response.Response.ID, config.ServiceProvider.SigningCertificate); ArtifactRedirect(destination, index, doc, relayState, cacheInsert); - } - - /// - /// Resolves an artifact. - /// - /// A stream containing the artifact response from the IdP - /// artifact from request ("SAMLart") - public Stream ResolveArtifact(string artifact, string relayState, Saml2Configuration config) + } + + /// + /// Resolves an artifact. + /// + /// A stream containing the artifact response from the IdP + /// artifact from request ("SAMLart") + /// + /// + public Stream ResolveArtifact(string artifact, string relayState, Saml2Configuration config) { var idpEndPoint = DetermineIdp(artifact); if (idpEndPoint == null) @@ -113,13 +116,14 @@ public Stream ResolveArtifact(string artifact, string relayState, Saml2Configura Logger.DebugFormat(TraceMessages.ArtifactResolved, artifactResolveString); return GetResponse(endpointUrl, artifactResolveString, idpEndPoint.ArtifactResolution, relayState); - } - - /// - /// Handles responses to an artifact resolve message. - /// - /// The artifact resolve message. - public void RespondToArtifactResolve(ArtifactResolve artifactResolve, XmlElement samlDoc) + } + + /// + /// Handles responses to an artifact resolve message. + /// + /// The artifact resolve message. + /// + public void RespondToArtifactResolve(ArtifactResolve artifactResolve, XmlElement samlDoc) { var response = Saml20ArtifactResponse.GetDefault(config.ServiceProvider.Id); response.StatusCode = Saml20Constants.StatusCodes.Success; @@ -156,16 +160,17 @@ private static bool ByteArraysAreEqual(byte[] a, byte[] b) } return true; - } - - /// - /// Handles all artifact creations and redirects. - /// - /// The destination. - /// Index of the local endpoint. - /// The signed SAML message. - /// The query string relay state value to add to the communication - private void ArtifactRedirect(IdentityProviderEndpoint destination, short localEndpointIndex, XmlDocument signedSamlMessage, string relayState, Action cacheInsert) + } + + /// + /// Handles all artifact creations and redirects. + /// + /// The destination. + /// Index of the local endpoint. + /// The signed SAML message. + /// The query string relay state value to add to the communication + /// + private void ArtifactRedirect(IdentityProviderEndpoint destination, short localEndpointIndex, XmlDocument signedSamlMessage, string relayState, Action cacheInsert) { Logger.DebugFormat(TraceMessages.ArtifactRedirectReceived, signedSamlMessage.OuterXml); @@ -174,9 +179,9 @@ private void ArtifactRedirect(IdentityProviderEndpoint destination, short localE var messageHandle = ArtifactUtil.GenerateMessageHandle(); var artifact = ArtifactUtil.CreateArtifact(HttpArtifactBindingConstants.ArtifactTypeCode, localEndpointIndex, sourceIdHash, messageHandle); - cacheInsert(artifact, signedSamlMessage); - - var destinationUrl = destination.Url + "?" + HttpArtifactBindingConstants.ArtifactQueryStringName + "=" + Uri.EscapeDataString(artifact); + cacheInsert(artifact, signedSamlMessage); + + var destinationUrl = string.Format( "{0}{1}{2}{3}{4}", destination.Url, ( destination.Url.EndsWith( "?" ) ? "&" : "?" ), HttpArtifactBindingConstants.ArtifactQueryStringName, "=", Uri.EscapeDataString( artifact ) ); if (!string.IsNullOrEmpty(relayState)) { destinationUrl += "&relayState=" + relayState; diff --git a/src/SAML2.Core/Config/Metadata.cs b/src/SAML2.Core/Config/Metadata.cs index 0db1103..0032f56 100644 --- a/src/SAML2.Core/Config/Metadata.cs +++ b/src/SAML2.Core/Config/Metadata.cs @@ -9,8 +9,6 @@ namespace SAML2.Config /// public class Metadata { - - /// /// Gets or sets a value indicating whether to exclude artifact endpoints in metadata generation. /// @@ -36,7 +34,12 @@ public class Metadata /// Gets or sets the requested attributes. /// /// The requested attributes. - public IList RequestedAttributes { get; set; } + public IList RequestedAttributes { get; set; } + + /// + /// Set Metadata validUntil attribute to be the days from now. The default is to ignore the validUntil attribute so the metadata will not expire. + /// + public int? ValidForDays { get; set; } public Metadata() { diff --git a/src/SAML2.Core/ErrorMessages.Designer.cs b/src/SAML2.Core/ErrorMessages.Designer.cs new file mode 100644 index 0000000..81603f4 --- /dev/null +++ b/src/SAML2.Core/ErrorMessages.Designer.cs @@ -0,0 +1,459 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.34209 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SAML2 { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class ErrorMessages { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal ErrorMessages() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SAML2.ErrorMessages", typeof(ErrorMessages).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Artifact is not from a known identity provider. + /// + public static string ArtifactResolveIdentityProviderUnknown { + get { + return ResourceManager.GetString("ArtifactResolveIdentityProviderUnknown", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Could not verify SAML SOAP binding message signature. + /// + public static string ArtifactResolveSignatureInvalid { + get { + return ResourceManager.GetString("ArtifactResolveSignatureInvalid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ArtifactResponse did not contain an assertion. + /// + public static string ArtifactResponseMissingAssertion { + get { + return ResourceManager.GetString("ArtifactResponseMissingAssertion", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unsupported payload message in ArtifactResponse. + /// + public static string ArtifactResponseMissingResponse { + get { + return ResourceManager.GetString("ArtifactResponseMissingResponse", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Could not verify artifact response message signature. + /// + public static string ArtifactResponseSignatureInvalid { + get { + return ResourceManager.GetString("ArtifactResponseSignatureInvalid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ArtifactResponse status code was invalid, expected {0}. + /// + public static string ArtifactResponseStatusCodeInvalid { + get { + return ResourceManager.GetString("ArtifactResponseStatusCodeInvalid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Assertion expiration has been exceeded. + /// + public static string AssertionExpired { + get { + return ResourceManager.GetString("AssertionExpired", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Could not process assertion with an unknown identity provider. + /// + public static string AssertionIdentityProviderUnknown { + get { + return ResourceManager.GetString("AssertionIdentityProviderUnknown", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Assertion not found. + /// + public static string AssertionNotFound { + get { + return ResourceManager.GetString("AssertionNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Assertion with OneTimeUse condition detected more than once. + /// + public static string AssertionOneTimeUseExceeded { + get { + return ResourceManager.GetString("AssertionOneTimeUseExceeded", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Assertion signature is invalid. + /// + public static string AssertionSignatureInvalid { + get { + return ResourceManager.GetString("AssertionSignatureInvalid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Attribute query can not be performed when user is not logged in with an identity provider. + /// + public static string AttrQueryNoLogin { + get { + return ResourceManager.GetString("AttrQueryNoLogin", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to AttrQuery response with status code "{0}" received when "Success" was expected. + /// + public static string AttrQueryStatusNotSuccessful { + get { + return ResourceManager.GetString("AttrQueryStatusNotSuccessful", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Certificate with DN "{0}" and thumbprint "{1}" is not valid according to RFC3280. + /// + public static string CertificateIsNotRFC3280Valid { + get { + return ResourceManager.GetString("CertificateIsNotRFC3280Valid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Certificate {0} was not found. + /// + public static string CertificateNotFound { + get { + return ResourceManager.GetString("CertificateNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Found more than one certificate matching {0}. + /// + public static string CertificateNotUnique { + get { + return ResourceManager.GetString("CertificateNotUnique", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Common Domain Cookie identity provider not found in list of known identity providers: {0}. + /// + public static string CommonDomainCookieIdentityProviderInvalid { + get { + return ResourceManager.GetString("CommonDomainCookieIdentityProviderInvalid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Configuration element <saml2> does not contain an <identityProviders> element. + /// + public static string ConfigMissingIdentityProvidersElement { + get { + return ResourceManager.GetString("ConfigMissingIdentityProvidersElement", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Configuration for <identityProviders> does not contain a "metadata" attribute. + /// + public static string ConfigMissingMetadataLocation { + get { + return ResourceManager.GetString("ConfigMissingMetadataLocation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Configuration does not contain <saml2> element. + /// + public static string ConfigMissingSaml2Element { + get { + return ResourceManager.GetString("ConfigMissingSaml2Element", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Configuration element <saml2> does not contain a <serviceProvider> element. + /// + public static string ConfigMissingServiceProviderElement { + get { + return ResourceManager.GetString("ConfigMissingServiceProviderElement", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Configuration for <serviceProvider> does not contain an "id" attribute. + /// + public static string ConfigMissingServiceProviderIdAttribute { + get { + return ResourceManager.GetString("ConfigMissingServiceProviderIdAttribute", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Configuration for <serviceProvider> does not contain a <signingCertificate> element. + /// + public static string ConfigMissingSigningCertificateElement { + get { + return ResourceManager.GetString("ConfigMissingSigningCertificateElement", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Configuration for <serviceProvider> does not contain a SignOn endpoint. + /// + public static string ConfigServiceProviderMissingSignOnEndpoint { + get { + return ResourceManager.GetString("ConfigServiceProviderMissingSignOnEndpoint", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Specified <signingCertificate> does not have a private key. + /// + public static string ConfigSigningCertificateMissingPrivateKey { + get { + return ResourceManager.GetString("ConfigSigningCertificateMissingPrivateKey", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The endpoint binding must be one of POST, Redirect, or Artifact. + /// + public static string EndpointBindingInvalid { + get { + return ResourceManager.GetString("EndpointBindingInvalid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Empty protocol message id is not allowed. + /// + public static string ExpectedInResponseToEmpty { + get { + return ResourceManager.GetString("ExpectedInResponseToEmpty", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Session ExpectedInResponseTo missing. + /// + public static string ExpectedInResponseToMissing { + get { + return ResourceManager.GetString("ExpectedInResponseToMissing", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to An error occurred. + /// + public static string GenericError { + get { + return ResourceManager.GetString("GenericError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The specified metadata directory "{0}" could not be located. + /// + public static string MetadataLocationNotFound { + get { + return ResourceManager.GetString("MetadataLocationNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The "sign"query string parameter could not be parsed. + /// + public static string MetadataSignQueryParameterInvalid { + get { + return ResourceManager.GetString("MetadataSignQueryParameterInvalid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Possible replay attack detected, unexpected value {0} for InResponseTo, expected {1}. + /// + public static string ReplayAttack { + get { + return ResourceManager.GetString("ReplayAttack", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Request signature is invalid. + /// + public static string RequestSignatureInvalid { + get { + return ResourceManager.GetString("RequestSignatureInvalid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Request is not signed. + /// + public static string RequestSignatureMissing { + get { + return ResourceManager.GetString("RequestSignatureMissing", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Received a response message that did not contain an InResponseTo attribute. + /// + public static string ResponseMissingInResponseToAttribute { + get { + return ResourceManager.GetString("ResponseMissingInResponseToAttribute", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Response signature is invalid. + /// + public static string ResponseSignatureInvalid { + get { + return ResourceManager.GetString("ResponseSignatureInvalid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Response is not signed. + /// + public static string ResponseSignatureMissing { + get { + return ResourceManager.GetString("ResponseSignatureMissing", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Response with status code NoPassive received. A user cannot be signed in with the IsPassiveFlag set when the user does not have a session with the identity provider. + /// + public static string ResponseStatusIsNoPassive { + get { + return ResourceManager.GetString("ResponseStatusIsNoPassive", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Response with status code "{0}" received when "Success"was expected. + /// + public static string ResponseStatusNotSuccessful { + get { + return ResourceManager.GetString("ResponseStatusNotSuccessful", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SOAP message did not contain a supported SamlMessage element. + /// + public static string SOAPMessageUnsupportedSamlMessage { + get { + return ResourceManager.GetString("SOAPMessageUnsupportedSamlMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to User accessing resource "{0}" without authentication. + /// + public static string UnauthenticatedAccess { + get { + return ResourceManager.GetString("UnauthenticatedAccess", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Encoding "{0}" is not supported. + /// + public static string UnknownEncoding { + get { + return ResourceManager.GetString("UnknownEncoding", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unknown identity provider "{0}". + /// + public static string UnknownIdentityProvider { + get { + return ResourceManager.GetString("UnknownIdentityProvider", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to RequestType "{0}" is not supported.. + /// + public static string UnsupportedRequestType { + get { + return ResourceManager.GetString("UnsupportedRequestType", resourceCulture); + } + } + } +} diff --git a/src/SAML2.Core/ErrorMessages.resx b/src/SAML2.Core/ErrorMessages.resx index 9f5b052..a7bad7d 100644 --- a/src/SAML2.Core/ErrorMessages.resx +++ b/src/SAML2.Core/ErrorMessages.resx @@ -1,252 +1,252 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Artifact is not from a known identity provider - - - Could not verify SAML SOAP binding message signature - - - ArtifactResponse did not contain an assertion - - - Unsupported payload message in ArtifactResponse - - - Could not verify artifact response message signature - - - ArtifactResponse status code was invalid, expected {0} - - - Assertion expiration has been exceeded - - - Could not process assertion with an unknown identity provider - - - Assertion not found - - - Assertion with OneTimeUse condition detected more than once - - - Assertion signature is invalid - - - Attribute query can not be performed when user is not logged in with an identity provider - - - AttrQuery response with status code "{0}" received when "Success" was expected - - - Certificate with DN "{0}" and thumbprint "{1}" is not valid according to RFC3280 - - - Certificate {0} was not found - - - Found more than one certificate matching {0} - - - Common Domain Cookie identity provider not found in list of known identity providers: {0} - - - Configuration element <saml2> does not contain an <identityProviders> element - - - Configuration for <identityProviders> does not contain a "metadata" attribute - - - Configuration does not contain <saml2> element - - - Configuration element <saml2> does not contain a <serviceProvider> element - - - Configuration for <serviceProvider> does not contain an "id" attribute - - - Configuration for <serviceProvider> does not contain a <signingCertificate> element - - - Configuration for <serviceProvider> does not contain a SignOn endpoint - - - Specified <signingCertificate> does not have a private key - - - The endpoint binding must be one of POST, Redirect, or Artifact - - - Empty protocol message id is not allowed - - - Session ExpectedInResponseTo missing - - - An error occurred - - - The specified metadata directory "{0}" could not be located - - - The "sign"query string parameter could not be parsed - - - Possible replay attack detected, unexpected value {0} for InResponseTo, expected {1} - - - Request signature is invalid - - - Request is not signed - - - Received a response message that did not contain an InResponseTo attribute - - - Response signature is invalid - - - Response is not signed - - - Response with status code NoPassive received. A user cannot be signed in with the IsPassiveFlag set when the user does not have a session with the identity provider - - - Response with status code "{0}" received when "Success"was expected - - - SOAP message did not contain a supported SamlMessage element - - - User accessing resource "{0}" without authentication - - - Encoding "{0}" is not supported - - - Unknown identity provider "{0}" - - - RequestType "{0}" is not supported. - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Artifact is not from a known identity provider + + + Could not verify SAML SOAP binding message signature + + + ArtifactResponse did not contain an assertion + + + Unsupported payload message in ArtifactResponse + + + Could not verify artifact response message signature + + + ArtifactResponse status code was invalid, expected {0} + + + Assertion expiration has been exceeded + + + Could not process assertion with an unknown identity provider + + + Assertion not found + + + Assertion with OneTimeUse condition detected more than once + + + Assertion signature is invalid + + + Attribute query can not be performed when user is not logged in with an identity provider + + + AttrQuery response with status code "{0}" received when "Success" was expected + + + Certificate with DN "{0}" and thumbprint "{1}" is not valid according to RFC3280 + + + Certificate {0} was not found + + + Found more than one certificate matching {0} + + + Common Domain Cookie identity provider not found in list of known identity providers: {0} + + + Configuration element <saml2> does not contain an <identityProviders> element + + + Configuration for <identityProviders> does not contain a "metadata" attribute + + + Configuration does not contain <saml2> element + + + Configuration element <saml2> does not contain a <serviceProvider> element + + + Configuration for <serviceProvider> does not contain an "id" attribute + + + Configuration for <serviceProvider> does not contain a <signingCertificate> element + + + Configuration for <serviceProvider> does not contain a SignOn endpoint + + + Specified <signingCertificate> does not have a private key + + + The endpoint binding must be one of POST, Redirect, or Artifact + + + Empty protocol message id is not allowed + + + Session ExpectedInResponseTo missing + + + An error occurred + + + The specified metadata directory "{0}" could not be located + + + The "sign"query string parameter could not be parsed + + + Possible replay attack detected, unexpected value {0} for InResponseTo, expected {1} + + + Request signature is invalid + + + Request is not signed + + + Received a response message that did not contain an InResponseTo attribute + + + Response signature is invalid + + + Response is not signed + + + Response with status code NoPassive received. A user cannot be signed in with the IsPassiveFlag set when the user does not have a session with the identity provider + + + Response with status code "{0}" received when "Success"was expected + + + SOAP message did not contain a supported SamlMessage element + + + User accessing resource "{0}" without authentication + + + Encoding "{0}" is not supported + + + Unknown identity provider "{0}" + + + RequestType "{0}" is not supported. + \ No newline at end of file diff --git a/src/SAML2.Core/Protocol/Utility.cs b/src/SAML2.Core/Protocol/Utility.cs index f863c46..bafa353 100644 --- a/src/SAML2.Core/Protocol/Utility.cs +++ b/src/SAML2.Core/Protocol/Utility.cs @@ -166,14 +166,15 @@ public static XmlDocument GetDecodedSamlResponse(string samlResponse, Encoding e logger.DebugFormat(TraceMessages.SamlResponseDecoded, samlResponse); return doc; - } - - /// - /// Gets the decrypted assertion. - /// - /// The elem. - /// The decrypted . - public static Saml20EncryptedAssertion GetDecryptedAssertion(XmlElement elem, Saml2Configuration config) + } + + /// + /// Gets the decrypted assertion. + /// + /// The elem. + /// + /// The decrypted . + public static Saml20EncryptedAssertion GetDecryptedAssertion(XmlElement elem, Saml2Configuration config) { logger.Debug(TraceMessages.EncryptedAssertionDecrypting); @@ -195,14 +196,15 @@ public static Status GetStatusElement(XmlElement element) { var statElem = element.GetElementsByTagName(Status.ElementName, Saml20Constants.Protocol)[0]; return Serialization.DeserializeFromXmlString(statElem.OuterXml); - } - - /// - /// Checks for replay attack. - /// - /// The context. - /// The element. - public static void CheckReplayAttack(XmlElement element, bool requireInResponseTo, IDictionary session) + } + + /// + /// Checks for replay attack. + /// + /// The element. + /// + /// + public static void CheckReplayAttack(XmlElement element, bool requireInResponseTo, IDictionary session) { logger.Debug(TraceMessages.ReplayAttackCheck); @@ -246,14 +248,16 @@ public static void AddExpectedResponse(Saml20AuthnRequest request, IDictionary - /// Deserializes an assertion, verifies its signature and logs in the user if the assertion is valid. - /// - /// The context. - /// The elem. - public static Saml20Assertion HandleAssertion(XmlElement elem, Saml2Configuration config, Func getFromCache, Action setInCache) + } + + /// + /// Deserializes an assertion, verifies its signature and logs in the user if the assertion is valid. + /// + /// The elem. + /// + /// + /// + public static Saml20Assertion HandleAssertion(XmlElement elem, Saml2Configuration config, Func getFromCache, Action setInCache) { logger.DebugFormat(TraceMessages.AssertionProcessing, elem.OuterXml); @@ -296,24 +300,31 @@ public static Saml20Assertion HandleAssertion(XmlElement elem, Saml2Configuratio logger.DebugFormat(TraceMessages.AssertionParsed, assertion.Id); return assertion; - } - - /// - /// Decrypts an encrypted assertion, and sends the result to the HandleAssertion method. - /// - /// The context. - /// The elem. - public static Saml20Assertion HandleEncryptedAssertion(XmlElement elem, Saml2Configuration config, Func getFromCache, Action setInCache) + } + + /// + /// Decrypts an encrypted assertion, and sends the result to the HandleAssertion method. + /// + /// The elem. + /// + /// + /// + public static Saml20Assertion HandleEncryptedAssertion(XmlElement elem, Saml2Configuration config, Func getFromCache, Action setInCache) { return HandleAssertion(GetDecryptedAssertion(elem, config).Assertion.DocumentElement, config, getFromCache, setInCache); - } - - /// - /// Handles the SOAP. - /// - /// The context. - /// The input stream. - public static void HandleSoap(HttpArtifactBindingBuilder builder, Stream inputStream, Saml2Configuration config, Action signonCallback, Func getFromCache, Action setInCache, IDictionary session) + } + + /// + /// Handles the SOAP. + /// + /// + /// The input stream. + /// + /// + /// + /// + /// + public static void HandleSoap(HttpArtifactBindingBuilder builder, Stream inputStream, Saml2Configuration config, Action signonCallback, Func getFromCache, Action setInCache, IDictionary session) { var parser = new HttpArtifactBindingParser(inputStream); logger.DebugFormat(TraceMessages.SOAPMessageParse, parser.SamlMessage.OuterXml); @@ -371,14 +382,18 @@ public static void HandleSoap(HttpArtifactBindingBuilder builder, Stream inputSt logger.ErrorFormat(ErrorMessages.SOAPMessageUnsupportedSamlMessage); throw new Saml20Exception(ErrorMessages.SOAPMessageUnsupportedSamlMessage); } - } - - - /// - /// Handle the authentication response from the IDP. - /// - /// The context. - public static Saml20Assertion HandleResponse(Saml2Configuration config, string samlResponse, IDictionary session, Func getFromCache, Action setInCache) + } + + + /// + /// Handle the authentication response from the IDP. + /// + /// + /// + /// + /// + /// + public static Saml20Assertion HandleResponse(Saml2Configuration config, string samlResponse, IDictionary session, Func getFromCache, Action setInCache) { var defaultEncoding = Encoding.UTF8; var doc = Utility.GetDecodedSamlResponse(samlResponse, defaultEncoding); diff --git a/src/SAML2.Core/SAML2.Core.csproj b/src/SAML2.Core/SAML2.Core.csproj index 92e6661..c1791a2 100644 --- a/src/SAML2.Core/SAML2.Core.csproj +++ b/src/SAML2.Core/SAML2.Core.csproj @@ -1,303 +1,303 @@ - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {75E5BAD2-A20C-43CC-B5C8-38004CEDBDFD} - Library - Properties - SAML2 - SAML2.Core - v4.5 - 512 - - ..\ - true - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - true - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - True - True - ErrorMessages.resx - - - - - - - - - - - - - - - - - True - True - Resources.resx - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - True - True - TraceMessages.resx - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PublicResXFileCodeGenerator - ErrorMessages.Designer.cs - Designer - - - PublicResXFileCodeGenerator - Resources.Designer.cs - - - PublicResXFileCodeGenerator - TraceMessages.Designer.cs - - - - + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {75E5BAD2-A20C-43CC-B5C8-38004CEDBDFD} + Library + Properties + SAML2 + SAML2.Core + v4.5 + 512 + + ..\ + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + true + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + ErrorMessages.resx + + + + + + + + + + + + + + + + + True + True + Resources.resx + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + TraceMessages.resx + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PublicResXFileCodeGenerator + ErrorMessages.Designer.cs + Designer + + + PublicResXFileCodeGenerator + Resources.Designer.cs + + + PublicResXFileCodeGenerator + TraceMessages.Designer.cs + + + + - + --> + \ No newline at end of file diff --git a/src/SAML2.Core/Saml20MetadataDocument.cs b/src/SAML2.Core/Saml20MetadataDocument.cs index 7b7d9c4..1cf3dc4 100644 --- a/src/SAML2.Core/Saml20MetadataDocument.cs +++ b/src/SAML2.Core/Saml20MetadataDocument.cs @@ -160,8 +160,8 @@ private void InitializeDocument(XmlDocument doc) } // TODO Decide how to handle several entities in one metadata file. - if (child.LocalName == EntitiesDescriptor.ElementName) { - throw new NotImplementedException(); + if (child.LocalName == EntitiesDescriptor.ElementName) { + throw new NotImplementedException( "Decide how to handle several entities in one metadata file" ); } } @@ -192,14 +192,16 @@ private static XmlDocument LoadFileAsXmlDocument(string filename, IEnumerable - /// Loads a file into an XmlDocument. If the loading or the signature check fails, the method will retry using another encoding. - /// - /// The filename. - /// The XML document. - private static XmlDocument LoadAsXmlDocument(IEnumerable encodings, Action docLoad, Action quirksModeDocLoad) + } + + /// + /// Loads a file into an XmlDocument. If the loading or the signature check fails, the method will retry using another encoding. + /// + /// + /// + /// + /// The XML document. + private static XmlDocument LoadAsXmlDocument(IEnumerable encodings, Action docLoad, Action quirksModeDocLoad) { var doc = new XmlDocument { PreserveWhitespace = true }; @@ -515,13 +517,14 @@ private static EntityDescriptor GetDefaultEntityInstance() }; return result; - } - - /// - /// Signs the document. - /// - /// The doc. - private static void SignDocument(XmlDocument doc, X509Certificate2 certificate) + } + + /// + /// Signs the document. + /// + /// The doc. + /// + private static void SignDocument(XmlDocument doc, X509Certificate2 certificate) { if (!certificate.HasPrivateKey) { @@ -560,8 +563,10 @@ private static void SignDocument(XmlDocument doc, X509Certificate2 certificate) private void ConvertToMetadata(Saml2Configuration config, KeyInfo keyInfo) { var entity = CreateDefaultEntity(); - entity.EntityID = config.ServiceProvider.Id; - entity.ValidUntil = DateTime.Now.AddDays(7); + entity.EntityID = config.ServiceProvider.Id; + + if( config.Metadata.ValidForDays.HasValue ) + entity.ValidUntil = DateTime.Now.AddDays(config.Metadata.ValidForDays.Value); var serviceProviderDescriptor = new SpSsoDescriptor { diff --git a/src/SAML2.Core/TraceMessages.Designer.cs b/src/SAML2.Core/TraceMessages.Designer.cs new file mode 100644 index 0000000..5af14ff --- /dev/null +++ b/src/SAML2.Core/TraceMessages.Designer.cs @@ -0,0 +1,531 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.34209 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SAML2 { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class TraceMessages { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal TraceMessages() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SAML2.TraceMessages", typeof(TraceMessages).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Artifact created: {0}. + /// + public static string ArtifactCreated { + get { + return ResourceManager.GetString("ArtifactCreated", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Artifact redirect received: {0}. + /// + public static string ArtifactRedirectReceived { + get { + return ResourceManager.GetString("ArtifactRedirectReceived", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Artifact resolved: {0}. + /// + public static string ArtifactResolved { + get { + return ResourceManager.GetString("ArtifactResolved", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Resolving artifact "{0}" from identity provider "{1}" endpoint "{2}". + /// + public static string ArtifactResolveForKnownIdentityProvider { + get { + return ResourceManager.GetString("ArtifactResolveForKnownIdentityProvider", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Artifact resolve received: {0}. + /// + public static string ArtifactResolveReceived { + get { + return ResourceManager.GetString("ArtifactResolveReceived", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sending response to artifact resolve request "{0}": {1}. + /// + public static string ArtifactResolveResponseSent { + get { + return ResourceManager.GetString("ArtifactResolveResponseSent", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Artifact response received: {0}. + /// + public static string ArtifactResponseReceived { + get { + return ResourceManager.GetString("ArtifactResponseReceived", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Assertion found: {0}. + /// + public static string AssertionFound { + get { + return ResourceManager.GetString("AssertionFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Assertion being parsed. + /// + public static string AssertionParse { + get { + return ResourceManager.GetString("AssertionParse", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Successfully parsed Assertion: {0}. + /// + public static string AssertionParsed { + get { + return ResourceManager.GetString("AssertionParsed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Assertion prehandler called. + /// + public static string AssertionPrehandlerCalled { + get { + return ResourceManager.GetString("AssertionPrehandlerCalled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Processing assertion: {0}. + /// + public static string AssertionProcessing { + get { + return ResourceManager.GetString("AssertionProcessing", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to AttrQuery assertion received: {0}. + /// + public static string AttrQueryAssertionReceived { + get { + return ResourceManager.GetString("AttrQueryAssertionReceived", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to AttrQuery sent to "{0}": {1}. + /// + public static string AttrQuerySent { + get { + return ResourceManager.GetString("AttrQuerySent", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Audience restriction validated for intended URIs {0} against allowed URIs {1}. + /// + public static string AudienceRestrictionValidated { + get { + return ResourceManager.GetString("AudienceRestrictionValidated", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to AuthRequest sent for identity provider "{0}" using binding "{1}". + /// + public static string AuthnRequestPrepared { + get { + return ResourceManager.GetString("AuthnRequestPrepared", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to AuthnRequest sent: {0}. + /// + public static string AuthnRequestSent { + get { + return ResourceManager.GetString("AuthnRequestSent", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Common domain cookie received: {0}. + /// + public static string CommonDomainCookieReceived { + get { + return ResourceManager.GetString("CommonDomainCookieReceived", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Redirect to SignOn endpoint found in Common Domain Cookie. + /// + public static string CommonDomainCookieRedirect { + get { + return ResourceManager.GetString("CommonDomainCookieRedirect", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Redirecting to Common Domain for identity provider discovery. + /// + public static string CommonDomainCookieRedirectForDiscovery { + get { + return ResourceManager.GetString("CommonDomainCookieRedirectForDiscovery", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Redirect to SignOn endpoint "{0}". + /// + public static string CommonDomainCookieRedirectNotFound { + get { + return ResourceManager.GetString("CommonDomainCookieRedirectNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to EncryptedAssertion Decrypted: {0}. + /// + public static string EncryptedAssertionDecrypted { + get { + return ResourceManager.GetString("EncryptedAssertionDecrypted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Decrypting EncryptedAssertion. + /// + public static string EncryptedAssertionDecrypting { + get { + return ResourceManager.GetString("EncryptedAssertionDecrypting", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to EncryptedAssertion found: {0}. + /// + public static string EncryptedAssertionFound { + get { + return ResourceManager.GetString("EncryptedAssertionFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Identity provider not found. Redirecting for identity provider selection. + /// + public static string IdentityProviderRedirect { + get { + return ResourceManager.GetString("IdentityProviderRedirect", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Identity provider retreived from Common Domain Cookie: {0}. + /// + public static string IdentityProviderRetreivedFromCommonDomainCookie { + get { + return ResourceManager.GetString("IdentityProviderRetreivedFromCommonDomainCookie", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Identity provider retreived from known providers: {0}. + /// + public static string IdentityProviderRetreivedFromDefault { + get { + return ResourceManager.GetString("IdentityProviderRetreivedFromDefault", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Identity provider retreived from IDPChoiceParamater: {0}. + /// + public static string IdentityProviderRetreivedFromQueryString { + get { + return ResourceManager.GetString("IdentityProviderRetreivedFromQueryString", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Redirecting to idpSelectionUrl for selection of identity provider: {0}. + /// + public static string IdentityProviderRetreivedFromSelection { + get { + return ResourceManager.GetString("IdentityProviderRetreivedFromSelection", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Executing Logout Actions. + /// + public static string LogoutActionsExecuting { + get { + return ResourceManager.GetString("LogoutActionsExecuting", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Logout handler called. + /// + public static string LogoutHandlerCalled { + get { + return ResourceManager.GetString("LogoutHandlerCalled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Successfully parsed Logout request: {0}. + /// + public static string LogoutRequestParsed { + get { + return ResourceManager.GetString("LogoutRequestParsed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Parsing Logout request POST binding message: {0}. + /// + public static string LogoutRequestPostBindingParse { + get { + return ResourceManager.GetString("LogoutRequestPostBindingParse", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Logout request received: {0}. + /// + public static string LogoutRequestReceived { + get { + return ResourceManager.GetString("LogoutRequestReceived", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Parsing Logout request Redirect binding message with signature algorithm {1} and signature {2}: {0}. + /// + public static string LogoutRequestRedirectBindingParse { + get { + return ResourceManager.GetString("LogoutRequestRedirectBindingParse", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Logout request sent for identity provider "{0}" using "{1}" binding: {2}. + /// + public static string LogoutRequestSent { + get { + return ResourceManager.GetString("LogoutRequestSent", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Successfully parsed Logout response: {0}. + /// + public static string LogoutResponseParsed { + get { + return ResourceManager.GetString("LogoutResponseParsed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Parsing Logout response POST binding message: {0}. + /// + public static string LogoutResponsePostBindingParse { + get { + return ResourceManager.GetString("LogoutResponsePostBindingParse", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Logout response received. + /// + public static string LogoutResponseReceived { + get { + return ResourceManager.GetString("LogoutResponseReceived", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Parsing Logout response Redirect binding message with signature algorithm {1} and signature {2}: {0}. + /// + public static string LogoutResponseRedirectBindingParse { + get { + return ResourceManager.GetString("LogoutResponseRedirectBindingParse", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Logout response sent: {0}. + /// + public static string LogoutResponseSent { + get { + return ResourceManager.GetString("LogoutResponseSent", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Metadata document being created. + /// + public static string MetadataDocumentBeingCreated { + get { + return ResourceManager.GetString("MetadataDocumentBeingCreated", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Metadata document successfully created. + /// + public static string MetadataDocumentCreated { + get { + return ResourceManager.GetString("MetadataDocumentCreated", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No replay attack detected. + /// + public static string ReplaceAttackCheckCleared { + get { + return ResourceManager.GetString("ReplaceAttackCheckCleared", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Checking for replay attack. + /// + public static string ReplayAttackCheck { + get { + return ResourceManager.GetString("ReplayAttackCheck", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Successfully decoded SamlResponse: {0}. + /// + public static string SamlResponseDecoded { + get { + return ResourceManager.GetString("SamlResponseDecoded", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SamlResponse decoding. + /// + public static string SamlResponseDecoding { + get { + return ResourceManager.GetString("SamlResponseDecoding", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SamlResponse received: {0}. + /// + public static string SamlResponseReceived { + get { + return ResourceManager.GetString("SamlResponseReceived", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Executing SignOn Actions. + /// + public static string SignOnActionsExecuting { + get { + return ResourceManager.GetString("SignOnActionsExecuting", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SignOn handler called. + /// + public static string SignOnHandlerCalled { + get { + return ResourceManager.GetString("SignOnHandlerCalled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Successfully processed signon request for "{1}" using NameIdFormat "{2}" for session "{0}". + /// + public static string SignOnProcessed { + get { + return ResourceManager.GetString("SignOnProcessed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Parsing SOAP message: {0}. + /// + public static string SOAPMessageParse { + get { + return ResourceManager.GetString("SOAPMessageParse", resourceCulture); + } + } + } +} diff --git a/src/SAML2.Core/TraceMessages.resx b/src/SAML2.Core/TraceMessages.resx index 1f40883..6339bb0 100644 --- a/src/SAML2.Core/TraceMessages.resx +++ b/src/SAML2.Core/TraceMessages.resx @@ -1,276 +1,276 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Artifact created: {0} - - - Artifact redirect received: {0} - - - Artifact resolved: {0} - - - Resolving artifact "{0}" from identity provider "{1}" endpoint "{2}" - - - Artifact resolve received: {0} - - - Sending response to artifact resolve request "{0}": {1} - - - Artifact response received: {0} - - - AttrQuery assertion received: {0} - - - AttrQuery sent to "{0}": {1} - - - AuthRequest sent for identity provider "{0}" using binding "{1}" - - - Common domain cookie received: {0} - - - Redirect to SignOn endpoint found in Common Domain Cookie - - - Redirect to SignOn endpoint "{0}" - - - Executing Logout Actions - - - Logout request received: {0} - - - Logout request sent for identity provider "{0}" using "{1}" binding: {2} - - - Executing SignOn Actions - - - Successfully processed signon request for "{1}" using NameIdFormat "{2}" for session "{0}" - - - Parsing SOAP message: {0} - - - Assertion found: {0} - - - Assertion being parsed - - - Successfully parsed Assertion: {0} - - - Assertion prehandler called - - - Processing assertion: {0} - - - Audience restriction validated for intended URIs {0} against allowed URIs {1} - - - AuthnRequest sent: {0} - - - Redirecting to Common Domain for identity provider discovery - - - EncryptedAssertion Decrypted: {0} - - - Decrypting EncryptedAssertion - - - EncryptedAssertion found: {0} - - - Identity provider not found. Redirecting for identity provider selection - - - Identity provider retreived from Common Domain Cookie: {0} - - - Identity provider retreived from known providers: {0} - - - Identity provider retreived from IDPChoiceParamater: {0} - - - Redirecting to idpSelectionUrl for selection of identity provider: {0} - - - Logout handler called - - - Successfully parsed Logout request: {0} - - - Parsing Logout request POST binding message: {0} - - - Parsing Logout request Redirect binding message with signature algorithm {1} and signature {2}: {0} - - - Successfully parsed Logout response: {0} - - - Parsing Logout response POST binding message: {0} - - - Logout response received - - - Parsing Logout response Redirect binding message with signature algorithm {1} and signature {2}: {0} - - - Logout response sent: {0} - - - Metadata document being created - - - Metadata document successfully created - - - No replay attack detected - - - Checking for replay attack - - - Successfully decoded SamlResponse: {0} - - - SamlResponse decoding - - - SamlResponse received: {0} - - - SignOn handler called - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Artifact created: {0} + + + Artifact redirect received: {0} + + + Artifact resolved: {0} + + + Resolving artifact "{0}" from identity provider "{1}" endpoint "{2}" + + + Artifact resolve received: {0} + + + Sending response to artifact resolve request "{0}": {1} + + + Artifact response received: {0} + + + AttrQuery assertion received: {0} + + + AttrQuery sent to "{0}": {1} + + + AuthRequest sent for identity provider "{0}" using binding "{1}" + + + Common domain cookie received: {0} + + + Redirect to SignOn endpoint found in Common Domain Cookie + + + Redirect to SignOn endpoint "{0}" + + + Executing Logout Actions + + + Logout request received: {0} + + + Logout request sent for identity provider "{0}" using "{1}" binding: {2} + + + Executing SignOn Actions + + + Successfully processed signon request for "{1}" using NameIdFormat "{2}" for session "{0}" + + + Parsing SOAP message: {0} + + + Assertion found: {0} + + + Assertion being parsed + + + Successfully parsed Assertion: {0} + + + Assertion prehandler called + + + Processing assertion: {0} + + + Audience restriction validated for intended URIs {0} against allowed URIs {1} + + + AuthnRequest sent: {0} + + + Redirecting to Common Domain for identity provider discovery + + + EncryptedAssertion Decrypted: {0} + + + Decrypting EncryptedAssertion + + + EncryptedAssertion found: {0} + + + Identity provider not found. Redirecting for identity provider selection + + + Identity provider retreived from Common Domain Cookie: {0} + + + Identity provider retreived from known providers: {0} + + + Identity provider retreived from IDPChoiceParamater: {0} + + + Redirecting to idpSelectionUrl for selection of identity provider: {0} + + + Logout handler called + + + Successfully parsed Logout request: {0} + + + Parsing Logout request POST binding message: {0} + + + Parsing Logout request Redirect binding message with signature algorithm {1} and signature {2}: {0} + + + Successfully parsed Logout response: {0} + + + Parsing Logout response POST binding message: {0} + + + Logout response received + + + Parsing Logout response Redirect binding message with signature algorithm {1} and signature {2}: {0} + + + Logout response sent: {0} + + + Metadata document being created + + + Metadata document successfully created + + + No replay attack detected + + + Checking for replay attack + + + Successfully decoded SamlResponse: {0} + + + SamlResponse decoding + + + SamlResponse received: {0} + + + SignOn handler called + \ No newline at end of file diff --git a/src/SAML2.Tests/Certificates/SafewhereTest_SFS.pfx b/src/SAML2.Tests/Certificates/SafewhereTest_SFS.pfx new file mode 100644 index 0000000..604649c Binary files /dev/null and b/src/SAML2.Tests/Certificates/SafewhereTest_SFS.pfx differ diff --git a/src/SAML2.Tests/Certificates/sts_dev_certificate.pfx b/src/SAML2.Tests/Certificates/sts_dev_certificate.pfx new file mode 100644 index 0000000..c78d2fb Binary files /dev/null and b/src/SAML2.Tests/Certificates/sts_dev_certificate.pfx differ diff --git a/src/SAML2.sln b/src/SAML2.sln index 72ae66d..20f69ee 100644 --- a/src/SAML2.sln +++ b/src/SAML2.sln @@ -1,46 +1,53 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.22310.1 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SAML2.Core", "SAML2.Core\SAML2.Core.csproj", "{75E5BAD2-A20C-43CC-B5C8-38004CEDBDFD}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SAML2.Tests", "SAML2.Tests\SAML2.Tests.csproj", "{39FE8EA4-860C-4A15-A09C-B5B9EEF8CFA2}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Owin.Security.Saml", "Owin.Security.Saml\Owin.Security.Saml.csproj", "{0054DAFD-1A69-4807-B24E-A6A6B71927C7}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SAML2.AspNet", "SAML2.AspNet\SAML2.AspNet.csproj", "{D2136BFD-D2DA-4105-920B-8E05C090C597}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SelfHostOwinSPExample", "SelfHostOwinSPExample\SelfHostOwinSPExample.csproj", "{6A489386-AFB0-4172-ACF4-61F79DC340DC}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {75E5BAD2-A20C-43CC-B5C8-38004CEDBDFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {75E5BAD2-A20C-43CC-B5C8-38004CEDBDFD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {75E5BAD2-A20C-43CC-B5C8-38004CEDBDFD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {75E5BAD2-A20C-43CC-B5C8-38004CEDBDFD}.Release|Any CPU.Build.0 = Release|Any CPU - {39FE8EA4-860C-4A15-A09C-B5B9EEF8CFA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {39FE8EA4-860C-4A15-A09C-B5B9EEF8CFA2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {39FE8EA4-860C-4A15-A09C-B5B9EEF8CFA2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {39FE8EA4-860C-4A15-A09C-B5B9EEF8CFA2}.Release|Any CPU.Build.0 = Release|Any CPU - {0054DAFD-1A69-4807-B24E-A6A6B71927C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0054DAFD-1A69-4807-B24E-A6A6B71927C7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0054DAFD-1A69-4807-B24E-A6A6B71927C7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0054DAFD-1A69-4807-B24E-A6A6B71927C7}.Release|Any CPU.Build.0 = Release|Any CPU - {D2136BFD-D2DA-4105-920B-8E05C090C597}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D2136BFD-D2DA-4105-920B-8E05C090C597}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D2136BFD-D2DA-4105-920B-8E05C090C597}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D2136BFD-D2DA-4105-920B-8E05C090C597}.Release|Any CPU.Build.0 = Release|Any CPU - {6A489386-AFB0-4172-ACF4-61F79DC340DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6A489386-AFB0-4172-ACF4-61F79DC340DC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6A489386-AFB0-4172-ACF4-61F79DC340DC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6A489386-AFB0-4172-ACF4-61F79DC340DC}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.40629.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SAML2.Core", "SAML2.Core\SAML2.Core.csproj", "{75E5BAD2-A20C-43CC-B5C8-38004CEDBDFD}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SAML2.Tests", "SAML2.Tests\SAML2.Tests.csproj", "{39FE8EA4-860C-4A15-A09C-B5B9EEF8CFA2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Owin.Security.Saml", "Owin.Security.Saml\Owin.Security.Saml.csproj", "{0054DAFD-1A69-4807-B24E-A6A6B71927C7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SAML2.AspNet", "SAML2.AspNet\SAML2.AspNet.csproj", "{D2136BFD-D2DA-4105-920B-8E05C090C597}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SelfHostOwinSPExample", "SelfHostOwinSPExample\SelfHostOwinSPExample.csproj", "{6A489386-AFB0-4172-ACF4-61F79DC340DC}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{3042234F-B95F-44EB-A228-C6EAE64F01B1}" + ProjectSection(SolutionItems) = preProject + .nuget\NuGet.Config = .nuget\NuGet.Config + .nuget\NuGet.exe = .nuget\NuGet.exe + .nuget\NuGet.targets = .nuget\NuGet.targets + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {75E5BAD2-A20C-43CC-B5C8-38004CEDBDFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {75E5BAD2-A20C-43CC-B5C8-38004CEDBDFD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {75E5BAD2-A20C-43CC-B5C8-38004CEDBDFD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {75E5BAD2-A20C-43CC-B5C8-38004CEDBDFD}.Release|Any CPU.Build.0 = Release|Any CPU + {39FE8EA4-860C-4A15-A09C-B5B9EEF8CFA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {39FE8EA4-860C-4A15-A09C-B5B9EEF8CFA2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39FE8EA4-860C-4A15-A09C-B5B9EEF8CFA2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {39FE8EA4-860C-4A15-A09C-B5B9EEF8CFA2}.Release|Any CPU.Build.0 = Release|Any CPU + {0054DAFD-1A69-4807-B24E-A6A6B71927C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0054DAFD-1A69-4807-B24E-A6A6B71927C7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0054DAFD-1A69-4807-B24E-A6A6B71927C7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0054DAFD-1A69-4807-B24E-A6A6B71927C7}.Release|Any CPU.Build.0 = Release|Any CPU + {D2136BFD-D2DA-4105-920B-8E05C090C597}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D2136BFD-D2DA-4105-920B-8E05C090C597}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D2136BFD-D2DA-4105-920B-8E05C090C597}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D2136BFD-D2DA-4105-920B-8E05C090C597}.Release|Any CPU.Build.0 = Release|Any CPU + {6A489386-AFB0-4172-ACF4-61F79DC340DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6A489386-AFB0-4172-ACF4-61F79DC340DC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6A489386-AFB0-4172-ACF4-61F79DC340DC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6A489386-AFB0-4172-ACF4-61F79DC340DC}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/SAML2.v12.suo b/src/SAML2.v12.suo new file mode 100644 index 0000000..3f2f14f Binary files /dev/null and b/src/SAML2.v12.suo differ diff --git a/src/SelfHostOwinSPExample/SeekableRequestBodyMiddleware.cs b/src/SelfHostOwinSPExample/SeekableRequestBodyMiddleware.cs new file mode 100644 index 0000000..7227d5f --- /dev/null +++ b/src/SelfHostOwinSPExample/SeekableRequestBodyMiddleware.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Owin; + +namespace SelfHostOwinSPExample { + /// + /// Self-Host Owin Request Body stream is not seekable by default unlike its counter part on IIS + /// + public class SeekableRequestBodyMiddleware : OwinMiddleware { + public SeekableRequestBodyMiddleware( OwinMiddleware next ) : base( next ) { } + + public async override Task Invoke( IOwinContext context ) { + ReplaceBodyWithMemoryStreamIfNotCanSeek( context.Request ); + await Next.Invoke( context ); + } + /// + /// In OWIN selfhost environment, Request.Body is using HttpRequestStream that is not rewindable, it is causing issues for other components in pipeline trying to access the body content. + /// + /// + private void ReplaceBodyWithMemoryStreamIfNotCanSeek( IOwinRequest request ) { + if( !request.Body.CanSeek ) { + var bodyStream = request.Body; + request.Body = new MemoryStream(); + bodyStream.CopyTo( request.Body ); + request.Body.Seek( 0, SeekOrigin.Begin ); + } + } + } +} diff --git a/src/SelfHostOwinSPExample/SelfHostOwinSPExample.csproj b/src/SelfHostOwinSPExample/SelfHostOwinSPExample.csproj index 4bcb46e..81f2ecc 100644 --- a/src/SelfHostOwinSPExample/SelfHostOwinSPExample.csproj +++ b/src/SelfHostOwinSPExample/SelfHostOwinSPExample.csproj @@ -1,96 +1,106 @@ - - - - - Debug - AnyCPU - {6A489386-AFB0-4172-ACF4-61F79DC340DC} - Exe - Properties - SelfHostOwinSPExample - SelfHostOwinSPExample - v4.5 - 512 - - - AnyCPU - true - full - false - bin\Debug\ - TRACE;DEBUG - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\packages\Microsoft.Owin.3.0.0\lib\net45\Microsoft.Owin.dll - - - ..\packages\Microsoft.Owin.Host.HttpListener.3.0.0\lib\net45\Microsoft.Owin.Host.HttpListener.dll - - - ..\packages\Microsoft.Owin.Hosting.3.0.0\lib\net45\Microsoft.Owin.Hosting.dll - - - ..\packages\Microsoft.Owin.Security.3.0.0\lib\net45\Microsoft.Owin.Security.dll - - - ..\packages\Microsoft.Owin.Security.Cookies.3.0.0\lib\net45\Microsoft.Owin.Security.Cookies.dll - - - ..\packages\Owin.1.0\lib\net40\Owin.dll - - - - - - - - - - - - - - - - - - - - Always - - - - - {0054dafd-1a69-4807-b24e-a6a6b71927c7} - Owin.Security.Saml - - - {75e5bad2-a20c-43cc-b5c8-38004cedbdfd} - SAML2.Core - - - - - - - + + + + + Debug + AnyCPU + {6A489386-AFB0-4172-ACF4-61F79DC340DC} + Exe + Properties + SelfHostOwinSPExample + SelfHostOwinSPExample + v4.5 + 512 + ..\ + true + + + AnyCPU + true + full + false + bin\Debug\ + TRACE;DEBUG + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Microsoft.Owin.3.0.0\lib\net45\Microsoft.Owin.dll + + + ..\packages\Microsoft.Owin.Host.HttpListener.3.0.0\lib\net45\Microsoft.Owin.Host.HttpListener.dll + + + ..\packages\Microsoft.Owin.Hosting.3.0.0\lib\net45\Microsoft.Owin.Hosting.dll + + + ..\packages\Microsoft.Owin.Security.3.0.0\lib\net45\Microsoft.Owin.Security.dll + + + ..\packages\Microsoft.Owin.Security.Cookies.3.0.0\lib\net45\Microsoft.Owin.Security.Cookies.dll + + + ..\packages\Owin.1.0\lib\net40\Owin.dll + + + + + + + + + + + + + + + + + + + + + Always + + + + + {0054dafd-1a69-4807-b24e-a6a6b71927c7} + Owin.Security.Saml + + + {75e5bad2-a20c-43cc-b5c8-38004cedbdfd} + SAML2.Core + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + --> \ No newline at end of file diff --git a/src/SelfHostOwinSPExample/Startup.cs b/src/SelfHostOwinSPExample/Startup.cs index ba667dc..880724a 100644 --- a/src/SelfHostOwinSPExample/Startup.cs +++ b/src/SelfHostOwinSPExample/Startup.cs @@ -1,83 +1,83 @@ -using System; -using System.Linq; -using Owin; -using SAML2.Config; -using System.IO; - -namespace SelfHostOwinSPExample -{ - internal partial class Startup - { - public void Configuration(IAppBuilder appBuilder) - { - var config = GetSamlConfiguration(); -#if TEST - config = TestEnvironmentConfiguration(); -#endif - - appBuilder.UseCookieAuthentication(new Microsoft.Owin.Security.Cookies.CookieAuthenticationOptions - { - AuthenticationType = "SAML2", - AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Active - }); - appBuilder.UseSamlAuthentication(new Owin.Security.Saml.SamlAuthenticationOptions - { - Configuration = config, - RedirectAfterLogin = "/core", - }); - appBuilder.Run(async c => { - if (c.Authentication.User != null && - c.Authentication.User.Identity != null && - c.Authentication.User.Identity.IsAuthenticated) { - await c.Response.WriteAsync(c.Authentication.User.Identity.Name + "\r\n"); - await c.Response.WriteAsync(c.Authentication.User.Identity.AuthenticationType + "\r\n"); - foreach (var claim in c.Authentication.User.Identities.SelectMany(i => i.Claims)) - await c.Response.WriteAsync(claim.Value + "\r\n"); - await c.Response.WriteAsync("authenticated"); - } else { - // trigger authentication - c.Authentication.Challenge(c.Authentication.GetAuthenticationTypes().Select(d => d.AuthenticationType).ToArray()); - } - return; - }); - } - - private Saml2Configuration GetSamlConfiguration() - { - var myconfig = new Saml2Configuration - { - ServiceProvider = new ServiceProvider - { - SigningCertificate = new System.Security.Cryptography.X509Certificates.X509Certificate2(FileEmbeddedResource("SelfHostOwinSPExample.sts_dev_certificate.pfx"), "test1234", System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.MachineKeySet), - Server = "https://localhost:44333/core", - Id = "https://localhost:44333/core" - }, - AllowedAudienceUris = new System.Collections.Generic.List(new[] { new Uri("https://localhost:44333/core") }) - }; - myconfig.ServiceProvider.Endpoints.AddRange(new[] { - new ServiceProviderEndpoint(EndpointType.SignOn, "/core/saml2/login", "/core"), - new ServiceProviderEndpoint(EndpointType.Logout, "/core/saml2/logout", "/core"), - new ServiceProviderEndpoint(EndpointType.Metadata, "/core/saml2/metadata") - }); - myconfig.IdentityProviders.AddByMetadataDirectory("..\\..\\Metadata"); - //myconfig.IdentityProviders.AddByMetadataUrl(new Uri("https://tas.fhict.nl/identity/saml2/metadata")); - myconfig.IdentityProviders.First().OmitAssertionSignatureCheck = true; - myconfig.LoggingFactoryType = "SAML2.Logging.DebugLoggerFactory"; - return myconfig; - } - - private byte[] FileEmbeddedResource(string path) - { - var assembly = System.Reflection.Assembly.GetExecutingAssembly(); - var resourceName = path; - - byte[] result = null; - using (Stream stream = assembly.GetManifestResourceStream(resourceName)) - using (var memoryStream = new MemoryStream()) { - stream.CopyTo(memoryStream); - result = memoryStream.ToArray(); - } - return result; - } - } +using System; +using System.Linq; +using Owin; +using SAML2.Config; +using System.IO; + +namespace SelfHostOwinSPExample +{ + internal partial class Startup + { + public void Configuration(IAppBuilder appBuilder) + { + var config = GetSamlConfiguration(); +#if TEST + config = TestEnvironmentConfiguration(); +#endif + appBuilder.Use(); + appBuilder.UseCookieAuthentication(new Microsoft.Owin.Security.Cookies.CookieAuthenticationOptions + { + AuthenticationType = "SAML2", + AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Active + }); + appBuilder.UseSamlAuthentication(new Owin.Security.Saml.SamlAuthenticationOptions + { + Configuration = config, + RedirectAfterLogin = "/core", + }); + appBuilder.Run(async c => { + if (c.Authentication.User != null && + c.Authentication.User.Identity != null && + c.Authentication.User.Identity.IsAuthenticated) { + await c.Response.WriteAsync(c.Authentication.User.Identity.Name + "\r\n"); + await c.Response.WriteAsync(c.Authentication.User.Identity.AuthenticationType + "\r\n"); + foreach (var claim in c.Authentication.User.Identities.SelectMany(i => i.Claims)) + await c.Response.WriteAsync(claim.Value + "\r\n"); + await c.Response.WriteAsync("authenticated"); + } else { + // trigger authentication + c.Authentication.Challenge(c.Authentication.GetAuthenticationTypes().Select(d => d.AuthenticationType).ToArray()); + } + return; + }); + } + + private Saml2Configuration GetSamlConfiguration() + { + var myconfig = new Saml2Configuration + { + ServiceProvider = new ServiceProvider + { + SigningCertificate = new System.Security.Cryptography.X509Certificates.X509Certificate2(FileEmbeddedResource("SelfHostOwinSPExample.sts_dev_certificate.pfx"), "test1234", System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.MachineKeySet), + Server = "https://localhost:44333/core", + Id = "https://www.testsamlgithub.com" + }, + AllowedAudienceUris = new System.Collections.Generic.List( new[] { new Uri( "https://www.testsamlgithub.com" ) } ) + }; + myconfig.ServiceProvider.Endpoints.AddRange(new[] { + new ServiceProviderEndpoint(EndpointType.SignOn, "/core/saml2/login", "/core"), + new ServiceProviderEndpoint(EndpointType.Logout, "/core/saml2/logout", "/core"), + new ServiceProviderEndpoint(EndpointType.Metadata, "/core/saml2/metadata") + }); + myconfig.IdentityProviders.AddByMetadataDirectory("..\\..\\Metadata"); + //myconfig.IdentityProviders.AddByMetadataUrl(new Uri("https://tas.fhict.nl/identity/saml2/metadata")); + myconfig.IdentityProviders.First().OmitAssertionSignatureCheck = true; + myconfig.LoggingFactoryType = "SAML2.Logging.DebugLoggerFactory"; + return myconfig; + } + + private byte[] FileEmbeddedResource(string path) + { + var assembly = System.Reflection.Assembly.GetExecutingAssembly(); + var resourceName = path; + + byte[] result = null; + using (Stream stream = assembly.GetManifestResourceStream(resourceName)) + using (var memoryStream = new MemoryStream()) { + stream.CopyTo(memoryStream); + result = memoryStream.ToArray(); + } + return result; + } + } } \ No newline at end of file diff --git a/src/SelfHostOwinSPExample/sts_dev_certificate.pfx b/src/SelfHostOwinSPExample/sts_dev_certificate.pfx new file mode 100644 index 0000000..c78d2fb Binary files /dev/null and b/src/SelfHostOwinSPExample/sts_dev_certificate.pfx differ diff --git a/src/packages/repositories.config b/src/packages/repositories.config new file mode 100644 index 0000000..4eb7a7c --- /dev/null +++ b/src/packages/repositories.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file