spring-boot-security-saml, Spring Security saml与 Spring Boot的集成

分享于 

25分钟阅读

GitHub

  繁體 雙語
spring-security-saml integration with Spring Boot
  • 源代码名称:spring-boot-security-saml
  • 源代码网址:http://www.github.com/ulisesbocchio/spring-boot-security-saml
  • spring-boot-security-saml源代码文档
  • spring-boot-security-saml源代码下载
  • Git URL:
    git://www.github.com/ulisesbocchio/spring-boot-security-saml.git
    Git Clone代码到本地:
    git clone http://www.github.com/ulisesbocchio/spring-boot-security-saml
    Subversion代码到本地:
    $ svn co --depth empty http://www.github.com/ulisesbocchio/spring-boot-security-saml
    Checked out revision 1.
    $ cd repo
    $ svn up trunk
    

    Build StatusGitterMaven Central

    spring-boot-security-saml

    这个项目在处理 spring-security-saml 和 Spring Boot 之间的平滑集成的同时,在处理内部的配置的gritty和锅炉板的同时,还提供了一系列。

    Spring Boot 1.4.0 + Spring Boot 1.5.0 +

    快速入门

    将以下 Maven 依赖项添加到项目中:

    <dependency>
     <groupId>com.github.ulisesbocchio</groupId>
     <artifactId>spring-boot-security-saml</artifactId>
     <version>1.15</version>
    </dependency>

    @EnableSAMLSSO 注释添加到任何 @Configuration 类中的Spring Boot 应用程序中:

    @SpringBootApplication@EnableSAMLSSOpublicclassServiceProviderApplication {
     ...}

    开始配置你的SAML 2.0服务提供者( 请参见下面的 。)。

    配置你的SAML 2.0服务提供商

    对于那些熟悉 spring-security-saml的人,这个插件通过 2种不同的形式公开了大部分的配置点,它们是完全可以互换的,并且在提供定制实现和实例。 两种配置风格包括:

    Java DSL

    使用 ServiceProviderConfigurerAdapter

    通过 JAVA DSL配置服务提供者非常简单,它遵循 Spring Security 目前拥有的configurer/adapter/builder 风格。 为配置提供了特定的接口和适配器类,这些类是: ServiceProviderConfigurerServiceProviderConfigurerAdapter。在大多数情况下,你应该简单地扩展 ServiceProviderConfigurerAdapter 并重写 #configure(ServiceProviderBuilder serviceProvider) 方法。这是一个示例:

    @ConfigurationpublicstaticclassMyServiceProviderConfigextendsServiceProviderConfigurerAdapter {
     @Overridepublicvoidconfigure(ServiceProviderBuilderserviceProvider) throwsException {
     // @formatter:off serviceProvider 
    . metadataGenerator() //(1). entityId("localhost-demo")
    . and()
    . sso() //(2). defaultSuccessURL("/home")
    . idpSelectionPageURL("/idpselection")
    . and()
    . logout() //(3). defaultTargetURL("/")
    . and()
    . metadataManager() //(4). metadataLocations("classpath:/idp-ssocircle.xml")
    . refreshCheckInterval(0)
    . and()
    . extendedMetadata() //(5). idpDiscoveryEnabled(true)
    . and()
    . keyManager() //(6). privateKeyDERLocation("classpath:/localhost.key.der")
    . publicKeyPEMLocation("classpath:/localhost.cert");
     // @formatter:on }
    }

    这个类不是一个 @Configuration 类,它也可能是一个 spring Bean。 插件将在应用程序上下文中公开,并相应地配置服务提供者。 在 configurer/adapter。#configure(HttpSecurity http)#configure(WebSecurity web) 中其他两种方法允许在不需要扩展其他 configurers/适配器的情况下定制安全性和 WebSecurity 对象,基本上是一个快捷的快捷方式。 在上面的示例中,你可以看到如何指定以下项:

    • 服务提供程序实体 ID
    • 登录之前,默认成功 URL ( 如果未保存请求,则在登录成功后通过IDP进行重定向) 和自定义IDP选择页URL用于选择和标识提供程序。
    • 缺省注销 URL,基本上是成功注销后要重定向的URL。
    • 用于向IDP发送请求并验证来自IDP的传入呼叫和元数据reflesh间隔( 0表示从不)的IDP元数据。
    • 在实际登录之前,我们将提供一个( 设置为 false 以使用默认的IDP ) 选择页面,在实际登录之前,我们将提示你。
    • 我们提供一个定制的private 密钥( DER格式) 和 public 证书( PEM格式),用于签署输出请求。 ( 也要在IDP侧配置)。

    这里配置与在配置属性部分中展示的配置等效。 有关更多文档和实用选项,请参阅 ServiceProviderBuilder的JavaDoc并阅读配置 cookbook 插件。

    使用 WebSecurityConfigurerAdapter

    为了完成与上面相同的配置,还可以使用常规 Spring Security WebSecurityConfigurerAdapter 为你的应用程序配置SAML身份验证,以及应用程序可能需要的其他安全配置。 为这里,除了创建常规 WebSecurityConfigurerAdapter 配置外,还需要一个 SAMLConfigurerBean 类型的bean,你可以将它的插入到 WebSecurityConfigurerAdapter 中。 下面是一个示例,展示了与前一节完全相同的配置:

    @ConfigurationpublicstaticclassMyServiceProviderConfigextendsWebSecurityConfigurerAdapter {
     @BeanSAMLConfigurerBeansaml() {
     returnnewSAMLConfigurerBean();
     }
     @BeanpublicAuthenticationManagerauthenticationManagerBean() throwsException {
     returnsuper.authenticationManagerBean();
     }
     @Overridepublicvoidconfigure(HttpSecurityhttp) throwsException {
     // @formatter:off http.httpBasic()
    . disable()
    . csrf()
    . disable()
    . anonymous()
    . and()
    . apply(saml())
    . serviceProvider()
    . metadataGenerator() //(1). entityId("localhost-demo")
    . and()
    . sso() //(2). defaultSuccessURL("/home")
    . idpSelectionPageURL("/idpselection")
    . and()
    . logout() //(3). defaultTargetURL("/")
    . and()
    . metadataManager() //(4). metadataLocations("classpath:/idp-ssocircle.xml")
    . refreshCheckInterval(0)
    . and()
    . extendedMetadata() //(5). idpDiscoveryEnabled(true)
    . and()
    . keyManager() //(6). privateKeyDERLocation("classpath:/localhost.key.der")
    . publicKeyPEMLocation("classpath:/localhost.cert")
    . http()
    . authorizeRequests()
    . requestMatchers(saml().endpointsMatcher())
    . permitAll()
    . and()
    . authorizeRequests()
    . anyRequest()
    . authenticated();
     // @formatter:on }
    }

    这基本上是 Spring Security的手动配置,它的中定义了 SAMLConfigurerBeanbean 并用作 HttpSecurity.apply() 注册configurer并返回 ServiceProviderBuilder的参数。 返回的ServiceProviderBuilder 与前面的示例中使用的类型相同 ServiceProviderConfigurerAdapter.configure 方法。在使用 ServiceProviderBuilder 之后,存在一个 http() 方法以返回 HttpSecurity 配置。 在示例中,行:

    http() // or just http. authorizeRequests()
    . requestMatchers(saml().endpointsMatcher())
    . permitAll()

    需要公开SAML服务提供方终结点。 如果你不需要指定它们,endpointsMatcher() 方法返回一个只包含端点的RequestMatcher,并将 MATCH 或者自定义的url指定为。

    配置属性

    通过配置属性配置服务提供者非常简单,大多数配置都可以通过这种方式实现。 存在的两个限制是: 你只能配置公开的属性,显然你不能提供不同的Spring Security SAML类/接口的具体实现或者实例。 if需要提供特定类型或者更动态的配置,你需要使用 DSL 方法,在配置过程中,你可以在任何动态或者自定义实现配置中使用DSL配置。 你可以混合两种口味。
    有关所有配置属性的完整列表,请参见这里文档。 不包括在这里以避免混乱。

    下面的属性Fragment是通过 application.yml的示例配置。

    saml:
     sso:
     default-success-url: /home #(1)idp-selection-page-url: /idpSelection #(2)metadata-generator:
     entity-id: localhost-demo #(3)logout:
     default-target-url:/#(4)idp:
     metadata-location: classpath:/idp-ssocircle.xml #(5) metadata-manager:
     refresh-check-interval: 0#(6)extended-metadata:
     idp-discovery-enabled: true #(7)key-manager:
     private-key-der-location: classpath:/localhost.key.der #(8)public-key-pem-location: classpath:/localhost.cert #(9)

    在上面的示例中,你可以看到如何指定以下项:

    • 默认成功 URL ( 如果未保存请求,则在登录成功后通过IDP进行重定向) 和
    • 登录前选择和标识提供程序的自定义IDP选择页 URL。
    • 服务提供程序实体 ID
    • 缺省注销 URL,基本上是成功注销后要重定向的URL。
    • 用于向IDP发送请求并验证来自IDP的传入呼叫的IDP元数据,
    • 和元数据reflesh间隔( 0表示从不)。
    • 在实际登录之前,我们将提供一个( 设置为 false 以使用默认的IDP ) 选择页面,在实际登录之前,我们将提示你。
    • 提供自定义 private 键( DER格式)
    • 和 public 证书( PEM格式),用于签名传出请求。 ( 也要在IDP侧配置)。

    只要想定义一个很好的ServiceProviderConfigurerAdapter,就可以选择在 @EnableSAMLSSO 端留下的配置和属性。

    如果需要使用标准的WebSecurityConfigurerAdapter 来配置 SAML,也可以使用属性,也可以这样做。 在上述属性中,你需要做的就是将 SAMLConfigurerBean 应用到 HttpSecurity,并禁用SAML端点的安全性:

    @ConfigurationpublicstaticclassMyServiceProviderConfigextendsWebSecurityConfigurerAdapter {
     @BeanSAMLConfigurerBeansaml() {
     returnnewSAMLConfigurerBean();
     }
     @BeanpublicAuthenticationManagerauthenticationManagerBean() throwsException {
     returnsuper.authenticationManagerBean();
     }
     @Overridepublicvoidconfigure(HttpSecurityhttp) throwsException {
     // @formatter:off http.httpBasic()
    . disable()
    . csrf()
    . disable()
    . anonymous()
    . and()
    . apply(saml())
    . http()
    . authorizeRequests()
    . requestMatchers(saml().endpointsMatcher())
    . permitAll()
    . and()
    . authorizeRequests()
    . anyRequest()
    . authenticated();
     // @formatter:on }
    }

    有关属性的更详细描述,请参见类 SAMLSSOPropertiesServiceProviderBuilder的JavaDoc。 有关配置示例,请参见配置 cookbook

    可以重写 bean

    下面的Bean类可以在使用这个插件时被覆盖。 只要在 spring 配置中的任何地方添加一个Bean声明:

    类 NAME DSL版本
    ExtendedMetadata----
    SAMLContextProviderDSLSAMLContextProviderImpl
    SAMLContextProviderLBDSLSAMLContextProviderLB
    KeyManager----
    MetadataManagerDSLMetadataManager
    MetadataGeneratorDSLMetadataGenerator
    SAMLProcessor----
    WebSSOProfileConsumerDSLWebSSOProfileConsumerImpl
    WebSSOProfileConsumerHoKImplDSLWebSSOProfileConsumerHoKImpl
    WebSSOProfileDSLWebSSOProfileImpl
    WebSSOProfileECPImplDSLWebSSOProfileECPImpl
    WebSSOProfileHoKImplDSLWebSSOProfileHoKImpl
    SingleLogoutProfileDSLSingleLogoutProfileImpl
    SAMLAuthenticationProviderDSLSAMLAuthenticationProvider
    SAMLBootstrap----
    ParserPool----
    SAMLLogger----

    spring-security-saml Bean类使用 @Autowire 插入依赖项,第二列显示同一类型的DSL版本,你可以使用和填充它们,或者实现你自己的populate/implement。 那些没有DSL版本的人是因为他们不需要一个。 这些bean被插件连接,而不是依赖自动装配。 下面是bean覆盖的示例:

    @BeanpublicSAMLContextProvider mySAMLContextProvider() {
     returnnewDSLSAMLContextProvider();
    }

    Spring MVC 配置

    IDP选择页。主页或者默认注销页的spring-boot-security-saml 未提供默认模板。 开发人员需要配置需要的模板引擎,并确保为这个插件配置的url通过 Spring MVC 解析。 例如,在演示应用程序中使用以下配置指定还映射到注销页面的索引页:

    @ConfigurationpublicstaticclassMvcConfigextendsWebMvcConfigurerAdapter {
     @OverridepublicvoidaddViewControllers(ViewControllerRegistryregistry) {
     registry.addViewController("/").setViewName("index");
     }
    }

    另一方面,演示应用程序中的idpSelection.htmlhome.html 通过启动自动配置的Thymeleaf隐式定义为 view controller。 有关如何配置 Spring MVC的详细信息,请访问mvc文档页面和启动应用程序的spring 站点的spring 文档。

    查看spring-boot-security-saml演示应用程序

    使用 spring-boot-security-saml-demo-dslspring-boot-security-saml-demo-props使用 Java DSL样式和配置特性样式来演示这个插件的工作。 另外,为使用 Okta的工作演示 checkout spring-boot-security-saml-demo-okta as。

    查看spring-security-saml-sample示例应用程序

    中,有一个完全工作的Spring Boot 应用程序与常规的Spring Security SAML和几个 idp (。SSOCircle,Ping标识,OKTA,OneLogin ) 集成。 在本示例中,你可以检查将 spring-security-saml 与 spring 引导集成所需的配置数量。

    配置 cookbook

    这些示例旨在通过这个插件来覆盖一些常见的Spring Security SAML配置场景,展示新配置风格的动态。 这并不意味着 Spring Security SAML或者 SAML 2.0标准的广泛文档。 有关 Spring Security SAML和 SAML 2.0的文档,请参阅进一步的文档。

    在负载平衡器后面配置你的应用程序

    为了在负载平衡器 spring-security-saml 后面使用 Spring Boot 应用程序成功重定向到适当的url,可以提供备用 SAMLContextProviderLB。 可以像这样通过 spring-boot-security-saml:1.12 和配置属性配置这个 bean:

    @ConfigurationpublicstaticclassMyServiceProviderConfigextendsServiceProviderConfigurerAdapter {
     @Overridepublicvoidconfigure(ServiceProviderBuilderserviceProvider) throwsException {
     serviceProvider
    . metadataGenerator()
    . entityId("localhost-demo")
    . and()
    . sso()
    . defaultSuccessURL("/home")
    . idpSelectionPageURL("/idpselection")
    . and()
    . logout()
    . defaultTargetURL("/")
    . and()
    . metadataManager()
    . metadataLocations("classpath:/idp-ssocircle.xml")
    . refreshCheckInterval(0)
    . and()
    . extendedMetadata()
    . idpDiscoveryEnabled(true)
    . and()
    . keyManager()
    . privateKeyDERLocation("classpath:/localhost.key.der")
    . publicKeyPEMLocation("classpath:/localhost.cert")
    . and()
    . samlContextProviderLb()
    . scheme("https")
    . contextPath("/")
    . serverName("www.example.com")
    . serverPort(443)
    . includeServerPortInRequestURL(false);
     }
     }

    或者使用属性:

    saml.sso.context-provider.lb.context-path=/saml.sso.context-provider.lb.include-server-port-in-request-url=falsesaml.sso.context-provider.lb.scheme=httpssaml.sso.context-provider.lb.server-name=www.example.comsaml.sso.context-provider.lb.server-port=443

    用户定义的SHA256签名

    某些idp如ADFS要求使用SHA256消息签名。 为此,你可以像这样覆盖 SAMLBootstrap bean:

    publicfinalclassCustomSAMLBootstrapextendsSAMLBootstrap {
     @OverridepublicvoidpostProcessBeanFactory(ConfigurableListableBeanFactorybeanFactory) throwsBeansException {
     super.postProcessBeanFactory(beanFactory);
     BasicSecurityConfiguration config = (BasicSecurityConfiguration) Configuration.getGlobalSecurityConfiguration();
     config.registerSignatureAlgorithmURI("RSA", SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256);
     config.setSignatureReferenceDigestMethod(SignatureConstants.ALGO_ID_DIGEST_SHA256);
     }
    }
    @BeanpublicstaticSAMLBootstrap SAMLBootstrap() {
     returnnewCustomSAMLBootstrap();
    }

    自定义SAML消息存储

    如果你希望提供自己的SAML存储,则默认情况下,spring-security-saml 将存储SAML消息,你可以使用定制的提供自定义。

    使用 DSL:

    @Overridepublicvoid configure(ServiceProviderBuilder serviceProvider) throws Exception {
     SAMLContextProviderImpl contextProvider =newSAMLContextProviderImpl();
     contextProvider.setStorageFactory(customMessageStorageFactory);
     serviceProvider
    . samlContextProvider(contextProvider);
     // rest of configuration}

    重写 SAMLContextProvider Bean:

    @BeanSAMLContextProvider mySamlContextProvider(SAMLMessageStorageFactory messageStorageFactory) {
     DSLSAMLContextProviderImpl contextProvider =newDSLSAMLContextProviderImpl();
     contextProvider.setStorageFactory(messageStorageFactory);
     return contextProvider;
    }

    配置绑定

    你可能希望设置与IDP一起使用的绑定,这是你可以通过DSL执行的操作:

    @Overridepublicvoid configure(ServiceProviderBuilder serviceProvider) throws Exception {
     WebSSOProfileOptions profileOptions =newWebSSOProfileOptions();
     //POST Bindings profileOptions.setBinding(SAMLConstants.SAML2_POST_BINDING_URI);
     //REDIRECT Bindings profileOptions.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI);
     serviceProvider
    . sso()
    . profileOptions(profileOptions);
     // rest of configuration}

    static SP元数据

    你可能希望静态定义服务提供程序元数据。 通常没有理由,因为通过DSL中的SP on配置API是相当丰富的,并根据指定的url生成。 但如果这是你喜欢设置你的SP的方式。 下面是如何实现该功能的示例配置:

    @ConfigurationpublicstaticclassMyServiceProviderConfigextendsServiceProviderConfigurerAdapter {
     @Overridepublicvoidconfigure(ServiceProviderBuilderserviceProvider) throwsException {
     // @formatter:off serviceProvider
    . metadataGenerator()
    . entityId("localhost-demo")
    . and()
    . sso()
    . defaultSuccessURL("/home")
    . idpSelectionPageURL("/idpselection")
    . and()
    . logout()
    . defaultTargetURL("/")
    . and()
    . metadataManager()
    . metadataLocations("classpath:/idp-ssocircle.xml")
    . localMetadataLocation("classpath:/sp-ssocircle.xml")
    . refreshCheckInterval(0)
    . and()
    . extendedMetadata()
    . idpDiscoveryEnabled(true)
    . and()
    . localExtendedMetadata()
    . securityProfile("metaiop")
    . sslSecurityProfile("pkix")
    . signMetadata(true)
    . signingKey("localhost")
    . encryptionKey("localhost")
    . requireArtifactResolveSigned(false)
    . requireLogoutRequestSigned(false)
    . idpDiscoveryEnabled(true)
    . and()
     //This Keystore contains also the public key of idp.ssocircle.com. keyManager()
    . storeLocation("classpath:/localhost.jks")
    . storePass("foobar")
    . defaultKey("localhost")
    . keyPassword("localhost", "foobar");
     // @formatter:on }
    }

    配置的一部分特别针对 static 本地元数据。 serviceProvider.metadataManager().localMetadataLocaltion("sp-ssocircle.xml") 以及在中指定的选项 serviceProvider.localExtendedMetadata() 注意,在指定这里选项时,不再使用 MetadataGeneratorFilter,因为服务提供程序元数据是静态指定的。 端点 /saml/metadata 将显示指定的static 元数据文件的内容。

    在 der/pem格式生成自签名的private/public 密钥对

    # KEY AND CERTopenssl genrsa -out localhost.key 2048
    openssl req -new -x509 -key localhost.key -out localhost.pem -days 3650 -subj/CN=localhost# PEM KEY to DERopenssl pkcs8 -topk8 -inform PEM -outform DER -in localhost.key -out localhost.key.der -nocrypt

    添加你自己的SAMLUserDetailsService

    要添加自定义 SAMLUserDetailsService,只需使用 ServiceProviderBuilder DSL中的authenticationProvider() 生成器:

    @ConfigurationpublicstaticclassMyServiceProviderConfigextendsServiceProviderConfigurerAdapter {
     @Overridepublicvoidconfigure(ServiceProviderBuilderserviceProvider) throwsException {
     serviceProvider
    . authenticationProvider()
    . userDetailsService(newMySAMLUserDetailsService());
     }
     }

    或者简单地为 SAMLUserDetailsService 实现添加一个bean定义:

    @BeanpublicSAMLUserDetailsService mySamlUserDetailsService() {
     returnnewMySAMLUserDetailsService();
    }

    进一步的文档

    关于特定于 Spring Security SAML的配置,请访问他们的文档参考文档。 对于 SAML 2.0文档,这些文档是很好的起点:

    Credits

    特别感谢:

    许可证

    Lincensed在许可证


    INT  BOO  引导  sam  整合  安全  
    相关文章