From 79d24690d182cd21f29e1b890e60086325173eaf Mon Sep 17 00:00:00 2001 From: Rob Date: Tue, 6 May 2014 10:15:33 -0700 Subject: [PATCH] Add Federation Metadata Endpoint for HRD --- .../Constants.cs | 1 + .../Endpoints.cs | 8 ++ .../FederationMetadataController.cs | 33 ++++- .../WSFederationMetadataGenerator.cs | 46 ++++++- .../Home/Index.cshtml.Designer.cs | 19 ++- .../App_LocalResources/Home/Index.cshtml.resx | 127 +++++++++--------- .../WebSite/App_Start/ProtocolConfig.cs | 6 + .../WebSite/Controller/HomeController.cs | 1 + src/OnPremise/WebSite/Views/Home/Index.cshtml | 4 + 9 files changed, 171 insertions(+), 74 deletions(-) diff --git a/src/Libraries/Thinktecture.IdentityServer.Core/Constants.cs b/src/Libraries/Thinktecture.IdentityServer.Core/Constants.cs index fdd3701f..cce7071b 100644 --- a/src/Libraries/Thinktecture.IdentityServer.Core/Constants.cs +++ b/src/Libraries/Thinktecture.IdentityServer.Core/Constants.cs @@ -58,6 +58,7 @@ public static class Roles public static class CacheKeys { public const string WSFedMetadata = "Cache_WSFedMetadata"; + public const string WSFedRPMetadata = "Cache_WSFedRPMetadata"; } } } diff --git a/src/Libraries/Thinktecture.IdentityServer.Core/Endpoints.cs b/src/Libraries/Thinktecture.IdentityServer.Core/Endpoints.cs index 83b7c3ae..33a10687 100644 --- a/src/Libraries/Thinktecture.IdentityServer.Core/Endpoints.cs +++ b/src/Libraries/Thinktecture.IdentityServer.Core/Endpoints.cs @@ -15,6 +15,7 @@ public class Endpoints public Uri WSFederation { get; set; } public Uri WSFederationHRD { get; set; } public Uri WSFederationMetadata { get; set; } + public Uri WSFederationRPMetadata { get; set; } public Uri WSTrustMex { get; set; } public Uri PrivacyNotice { get; set; } @@ -43,6 +44,7 @@ public static class Paths public const string WSFedHRDSelect = "issue/hrd/select"; public const string WSFedHRDSignoutRedirect = "issue/hrd/SignoutRedirect"; public const string WSFedMetadata = "FederationMetadata/2007-06/FederationMetadata.xml"; + public const string WSFedRPMetadata = "FederationMetadataRP/2007-06/FederationMetadata.xml"; public const string PrivacyNotice = "privacyNotice.txt"; public const string WSTrustBase = "issue/wstrust"; public const string SimpleHttp = "issue/simple"; @@ -164,6 +166,12 @@ public static Endpoints Create(string baseUriString, int httpPort, int httpsPort builder.Scheme = Uri.UriSchemeHttps; builder.Port = httpsPort; ep.WSFederationMetadata = builder.Uri; + + var wsfedrpmd = new Uri(baseUriString + Paths.WSFedRPMetadata); + builder = new UriBuilder(wsfedrpmd); + builder.Scheme = Uri.UriSchemeHttps; + builder.Port = httpsPort; + ep.WSFederationRPMetadata = builder.Uri; var adfs = new Uri(baseUriString + Paths.AdfsIntegration); builder = new UriBuilder(adfs); diff --git a/src/Libraries/Thinktecture.IdentityServer.Protocols/FederationMetadata/FederationMetadataController.cs b/src/Libraries/Thinktecture.IdentityServer.Protocols/FederationMetadata/FederationMetadataController.cs index a674fd16..e200b0f9 100644 --- a/src/Libraries/Thinktecture.IdentityServer.Protocols/FederationMetadata/FederationMetadataController.cs +++ b/src/Libraries/Thinktecture.IdentityServer.Protocols/FederationMetadata/FederationMetadataController.cs @@ -5,7 +5,6 @@ using System; using System.ComponentModel.Composition; -using System.Web; using System.Web.Mvc; using Thinktecture.IdentityServer.Helper; using Thinktecture.IdentityServer.Repositories; @@ -60,5 +59,35 @@ public ActionResult Generate() return new HttpNotFoundResult(); } } + + public ActionResult GenerateRPMetadata() + { + if (ConfigurationRepository.FederationMetadata.Enabled) + { + return Cache.ReturnFromCache(CacheRepository, Constants.CacheKeys.WSFedRPMetadata, 1, () => + { + var host = ConfigurationRepository.Global.PublicHostName; + if (String.IsNullOrWhiteSpace(host)) + { + host = HttpContext.Request.Headers["Host"]; + } + var endpoints = Endpoints.Create( + host, + HttpContext.Request.ApplicationPath, + ConfigurationRepository.Global.HttpPort, + ConfigurationRepository.Global.HttpsPort); + + return new ContentResult + { + Content = new WSFederationMetadataGenerator(endpoints).GenerateRelyingPartyMetadata(), + ContentType = "text/xml" + }; + }); + } + else + { + return new HttpNotFoundResult(); + } + } } -} +} \ No newline at end of file diff --git a/src/Libraries/Thinktecture.IdentityServer.Protocols/FederationMetadata/WSFederationMetadataGenerator.cs b/src/Libraries/Thinktecture.IdentityServer.Protocols/FederationMetadata/WSFederationMetadataGenerator.cs index 37151574..30a56543 100644 --- a/src/Libraries/Thinktecture.IdentityServer.Protocols/FederationMetadata/WSFederationMetadataGenerator.cs +++ b/src/Libraries/Thinktecture.IdentityServer.Protocols/FederationMetadata/WSFederationMetadataGenerator.cs @@ -43,28 +43,47 @@ public WSFederationMetadataGenerator(Endpoints endpoints) Container.Current.SatisfyImportsOnce(this); } + //Builds federation metadata for using Id Srv as an IdP using the wsfed endpoint public string Generate() { - var tokenServiceDescriptor = GetTokenServiceDescriptor(); + var tokenServiceDescriptor = GetTokenServiceDescriptor(_endpoints.WSFederation.AbsoluteUri); + return GenerateMetadata(tokenServiceDescriptor); + } + + //Builds federation metadata for using Id Srv as an RP using the HRD endpoint + public string GenerateRelyingPartyMetadata() + { + var tokenServiceDescriptor = GetTokenServiceDescriptor(_endpoints.WSFederationHRD.AbsoluteUri); + var appServiceDescriptor = GetApplicationServiceDescriptor(); + + return GenerateMetadata(tokenServiceDescriptor, appServiceDescriptor); + } + + private string GenerateMetadata(params RoleDescriptor[] roles) + { var id = new EntityId(ConfigurationRepository.Global.IssuerUri); var entity = new EntityDescriptor(id); entity.SigningCredentials = new X509SigningCredentials(ConfigurationRepository.Keys.SigningCertificate); - entity.RoleDescriptors.Add(tokenServiceDescriptor); + foreach (var roleDescriptor in roles) + { + entity.RoleDescriptors.Add(roleDescriptor); + } + var ser = new MetadataSerializer(); var sb = new StringBuilder(512); ser.WriteMetadata(XmlWriter.Create(new StringWriter(sb), new XmlWriterSettings { OmitXmlDeclaration = true }), entity); return sb.ToString(); } - - private SecurityTokenServiceDescriptor GetTokenServiceDescriptor() + + private SecurityTokenServiceDescriptor GetTokenServiceDescriptor(string passiveRequestorEndpoint) { var tokenService = new SecurityTokenServiceDescriptor(); tokenService.ServiceDescription = ConfigurationRepository.Global.SiteName; tokenService.Keys.Add(GetSigningKeyDescriptor()); - tokenService.PassiveRequestorEndpoints.Add(new EndpointReference(_endpoints.WSFederation.AbsoluteUri)); + tokenService.PassiveRequestorEndpoints.Add(new EndpointReference(passiveRequestorEndpoint)); tokenService.TokenTypesOffered.Add(new Uri(TokenTypes.OasisWssSaml11TokenProfile11)); tokenService.TokenTypesOffered.Add(new Uri(TokenTypes.OasisWssSaml2TokenProfile11)); @@ -101,6 +120,23 @@ private SecurityTokenServiceDescriptor GetTokenServiceDescriptor() return tokenService; } + private ApplicationServiceDescriptor GetApplicationServiceDescriptor() + { + var appDescriptor = new ApplicationServiceDescriptor(); + + appDescriptor.ServiceDescription = ConfigurationRepository.Global.SiteName; + appDescriptor.Keys.Add(GetSigningKeyDescriptor()); + + appDescriptor.PassiveRequestorEndpoints.Add(new EndpointReference(_endpoints.WSFederationHRD.AbsoluteUri)); + appDescriptor.TokenTypesOffered.Add(new Uri(TokenTypes.OasisWssSaml11TokenProfile11)); + appDescriptor.TokenTypesOffered.Add(new Uri(TokenTypes.OasisWssSaml2TokenProfile11)); + + ClaimsRepository.GetSupportedClaimTypes().ToList().ForEach(claimType => appDescriptor.ClaimTypesOffered.Add(new DisplayClaim(claimType))); + appDescriptor.ProtocolsSupported.Add(new Uri("http://docs.oasis-open.org/wsfed/federation/200706")); + + return appDescriptor; + } + private KeyDescriptor GetSigningKeyDescriptor() { var certificate = ConfigurationRepository.Keys.SigningCertificate; diff --git a/src/OnPremise/WebSite/App_LocalResources/Home/Index.cshtml.Designer.cs b/src/OnPremise/WebSite/App_LocalResources/Home/Index.cshtml.Designer.cs index 00ce2d12..6344cb3e 100644 --- a/src/OnPremise/WebSite/App_LocalResources/Home/Index.cshtml.Designer.cs +++ b/src/OnPremise/WebSite/App_LocalResources/Home/Index.cshtml.Designer.cs @@ -1,17 +1,17 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.18033 +// Runtime Version:4.0.30319.18449 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ -namespace Thinktecture.IdentityServer.Web.App_LocalResources.Home -{ - - +namespace Thinktecture.IdentityServer.Web.App_LocalResources.Home { + using System; + + /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -78,6 +78,15 @@ public static string ViewWsFederationMetadata { } } + /// + /// Looks up a localized string similar to View WS-Federation Metadata (RP). + /// + public static string ViewWSFederationMetadataRP { + get { + return ResourceManager.GetString("ViewWSFederationMetadataRP", resourceCulture); + } + } + /// /// Looks up a localized string similar to Welcome to {0}. /// diff --git a/src/OnPremise/WebSite/App_LocalResources/Home/Index.cshtml.resx b/src/OnPremise/WebSite/App_LocalResources/Home/Index.cshtml.resx index 53e4c485..2613e42c 100644 --- a/src/OnPremise/WebSite/App_LocalResources/Home/Index.cshtml.resx +++ b/src/OnPremise/WebSite/App_LocalResources/Home/Index.cshtml.resx @@ -1,6 +1,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + Application integration - + View WS-Federation Metadata - + + View WS-Federation Metadata (RP) + + Welcome to {0} \ No newline at end of file diff --git a/src/OnPremise/WebSite/App_Start/ProtocolConfig.cs b/src/OnPremise/WebSite/App_Start/ProtocolConfig.cs index d418f694..2fbde72b 100644 --- a/src/OnPremise/WebSite/App_Start/ProtocolConfig.cs +++ b/src/OnPremise/WebSite/App_Start/ProtocolConfig.cs @@ -26,6 +26,12 @@ public static void RegisterProtocols(HttpConfiguration httpConfiguration, RouteC // federation metadata if (configuration.FederationMetadata.Enabled) { + routes.MapRoute( + "FederationMetadataRP", + Thinktecture.IdentityServer.Endpoints.Paths.WSFedRPMetadata, + new { controller = "FederationMetadata", action = "GenerateRPMetadata" } + ); + routes.MapRoute( "FederationMetadata", Thinktecture.IdentityServer.Endpoints.Paths.WSFedMetadata, diff --git a/src/OnPremise/WebSite/Controller/HomeController.cs b/src/OnPremise/WebSite/Controller/HomeController.cs index 4c4545b5..9abae234 100644 --- a/src/OnPremise/WebSite/Controller/HomeController.cs +++ b/src/OnPremise/WebSite/Controller/HomeController.cs @@ -56,6 +56,7 @@ public ActionResult AppIntegration() if (Configuration.FederationMetadata.Enabled) { list.Add("WS-Federation metadata", endpoints.WSFederationMetadata.AbsoluteUri); + list.Add("WS-Federation metadata (RP)", endpoints.WSFederationRPMetadata.AbsoluteUri); } // ws-federation diff --git a/src/OnPremise/WebSite/Views/Home/Index.cshtml b/src/OnPremise/WebSite/Views/Home/Index.cshtml index ea469246..1956c4ef 100644 --- a/src/OnPremise/WebSite/Views/Home/Index.cshtml +++ b/src/OnPremise/WebSite/Views/Home/Index.cshtml @@ -9,6 +9,10 @@ @Html.ActionLink(Index_cshtml.ViewWsFederationMetadata, "Generate", "FederationMetadata")

+

+ @Html.ActionLink(Index_cshtml.ViewWSFederationMetadataRP, "GenerateRPMetadata", "FederationMetadata") +

+

@Html.ActionLink(Index_cshtml.ApplicationIntegration, "appintegration", "home")

\ No newline at end of file