当前位置: 首页 > 知识库问答 >
问题:

Spring Security SAML和UserDetailsService

梁才
2023-03-14

我正在使用Spring Security 5.6内置的实现将SAML集成到一个Spring Boot应用程序中。许多在线帮助都引用了现在已被弃用的外部库实现(https://github.com/spring-projects/spring-security-saml ),所以我遵循这个文档:

https://docs.spring.io/spring-security/reference/servlet/saml2/login/index.html

我有这个交互工作,我现在正在从SAML进行身份验证。这是配置:

spring:
  security:
    saml2:
      relyingparty:
        registration:
          adfs:
            signing:
              credentials:
                - private-key-location: "file:///C:/tmp/keys/private.key"
                  certificate-location: "file:///C:/tmp/keys/public.crt"
            identityprovider:
              entity-id: << SNIPPED >>
              verification.credentials:
                - certificate-location: "classpath:saml-certificate/adfs.crt"
              singlesignon:
                url: << SNIPPED >>
                sign-request: true

代码现在如下所示:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    private final RelyingPartyRegistrationRepository _relyingPartyRegistrationRepository;

    @Autowired
    public WebSecurityConfig(RelyingPartyRegistrationRepository relyingPartyRegistrationRepository {
        _relyingPartyRegistrationRepository = relyingPartyRegistrationRepository;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // add auto-generation of ServiceProvider Metadata at {baseUrl}/saml2/service-provider-metadata/ims-adfs
        RelyingPartyRegistrationResolver relyingPartyRegistrationResolver = new DefaultRelyingPartyRegistrationResolver(_relyingPartyRegistrationRepository);
        Saml2MetadataFilter filter = new Saml2MetadataFilter(relyingPartyRegistrationResolver, new OpenSamlMetadataResolver());

        http
                .authorizeRequests()
                .antMatchers("/seer.ico", "/monitor", "/**/check").permitAll()
                .anyRequest().authenticated()
                .and().sessionManagement()
                .and().csrf().ignoringAntMatchers("/servers/**/searches")
                .and()
                .saml2Login(withDefaults())
                .saml2Logout(withDefaults())
                .addFilterBefore(filter, Saml2WebSsoAuthenticationFilter.class);
    }

}

问题是我需要重新映射用户详细信息以设置正确的角色,并将登录限制为具有正确 Linux 权限的用户。正在更正断言中返回的权限;我只需要验证它们是否正确或登录失败。

Spring Security文档中有一节是关于与UserDetailsService协调的,这似乎正是我所需要的。

https://docs.spring.io/spring-security/reference/servlet/saml2/login/authentication.html#servlet-saml2login-opensamlauthenticationprovider-userdetailsservice

但是,当我像示例一样实现它时,我现在从Spring收到以下错误:

响应中找不到断言。

以下是更新的代码

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    private final RelyingPartyRegistrationRepository _relyingPartyRegistrationRepository;

    private final AuthenticationService _userDetailsService;

    @Autowired
    public WebSecurityConfig(RelyingPartyRegistrationRepository relyingPartyRegistrationRepository, AuthenticationService userDetailsService) {
        _relyingPartyRegistrationRepository = relyingPartyRegistrationRepository;
        _userDetailsService = userDetailsService;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
         OpenSaml4AuthenticationProvider authenticationProvider = new OpenSaml4AuthenticationProvider();
         authenticationProvider.setResponseAuthenticationConverter(responseToken -> {
             Saml2Authentication authentication = OpenSaml4AuthenticationProvider.createDefaultResponseAuthenticationConverter().convert(responseToken);

             Assertion assertion = responseToken.getResponse().getAssertions().get(0);
             String username = assertion.getSubject().getNameID().getValue();

             UserDetails userDetails = _userDetailsService.loadUserByUsername(username);
             authentication.setDetails(userDetails);

             return authentication;
         });

        // add auto-generation of ServiceProvider Metadata at {baseUrl}/saml2/service-provider-metadata/ims-adfs
        RelyingPartyRegistrationResolver relyingPartyRegistrationResolver = new DefaultRelyingPartyRegistrationResolver(_relyingPartyRegistrationRepository);
        Saml2MetadataFilter filter = new Saml2MetadataFilter(relyingPartyRegistrationResolver, new OpenSamlMetadataResolver());

        http
                .authorizeRequests()
                .antMatchers("/seer.ico", "/monitor", "/**/check").permitAll()
                .anyRequest().authenticated()
                .and().sessionManagement()
                .and().csrf().ignoringAntMatchers("/servers/**/searches")
                .and()
                .saml2Login(saml2 -> saml2.authenticationManager(new ProviderManager(authenticationProvider)))
                .saml2Logout(withDefaults())
                .addFilterBefore(filter, Saml2WebSsoAuthenticationFilter.class);
    }
}

所以基本上这从SAML得到了正确的响应:

.saml2Login(withDefaults())

当我将其切换到此时,SAML 响应缺少断言:

.saml2Login(saml2 -> saml2.authenticationManager(new ProviderManager(authenticationProvider)))

我一直在寻找其他解决方案,但正如我所说,很少有示例不使用旧的不推荐使用的SAML库。

有什么想法吗?

共有1个答案

柯建修
2023-03-14

检查Spring Boot是否正在导入Open SAML的版本3和版本4。如果是,则仅使用版本4。

Spring Security Samples有一个SAML2的示例。项目中的build.gradle包含以下内容:

repositories {
    mavenCentral()
    maven { url "https://repo.spring.io/milestone" }
    maven { url "https://repo.spring.io/snapshot" }
    maven { url "https://build.shibboleth.net/nexus/content/repositories/releases/" }
}

dependencies {
    constraints {
        implementation "org.opensaml:opensaml-core:4.1.1"
        implementation "org.opensaml:opensaml-saml-api:4.1.1"
        implementation "org.opensaml:opensaml-saml-impl:4.1.1"
    }
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.security:spring-security-saml2-service-provider'
    implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6'

    testImplementation 'net.sourceforge.htmlunit:htmlunit:2.44.0'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'org.springframework.security:spring-security-test'
    testImplementation 'org.awaitility:awaitility:4.2.0'
}

引用:

  • 在Spring Security SAML2中自定义OpenSaml4AuthenticationProvider
  • https://github.com/spring-projects/spring-security-samples/blob/main/servlet/spring-boot/java/saml2/login/build.gradle
  • https://docs.spring.io/spring-security/reference/servlet/saml2/login/authentication.html
 类似资料:
  • 我是Spring Security的新手,我试图实现自定义的身份验证。令我困扰的是,这个接口只包含一个方法,它只将用户名作为参数并返回。 我想知道为什么这个方法不接受任何密码作为参数。 Spring是如何只根据用户名对用户进行身份验证的?

  • 问题内容: 关于它们有很多传说。我想知道真相。以下两个示例之间有什么区别? 问题答案: 不确定从何处获得传说,但: 提交按钮 与: IE6将在标记之间提交此按钮的所有文本,其他浏览器将仅提交值。使用可使您在按钮的设计上享有更大的布局自由度。从各种意图和目的看,它乍一看似乎很棒,但是各种浏览器怪癖使它有时很难使用。 在您的示例中,IE6将发送到服务器,而其他大多数浏览器将不发送任何内容。要使其跨浏览

  • 什么区别以及如何正确重写代码?

  • 我试图理解为什么下面两个代码块会产生不同的结果。 代码块1按预期工作,并返回从数据库中查找的提供程序的数组。另一方面,代码块2返回函数数组。在理解promissione.all()和async/await时,我觉得缺少了一些简单的东西。 代码块的差异如下: > 块1:创建许诺函数数组,然后使用map运算符将其包装在异步函数中。 块2:许诺函数的数组被创建为异步函数。因此,不调用map运算符。 如果

  • 问题内容: 我才刚刚开始研究SQL。 我有一个SQL Server 2008r2数据库,它将返回两个字段DocDate和InvValue。我需要将InvValues汇总为今天的MTD和YTD,所以看起来像 我已经做了大量的Google搜寻,并且可以使用SUM&DATEPART进行一项或多项,但是我坚持尝试两者兼而有之。 有人可以给我一些伪代码,以帮助我进一步谷歌。 谢谢@戈登·利诺夫(Gordon

  • 这个示例代码来自一本Java书籍,从墙上的99瓶啤酒到没有啤酒打印出这首歌。问题是,当墙上是1瓶啤酒时,它仍然写着瓶子。我试图通过在末尾添加部分来解决这个问题。但是,它仍然显示1瓶啤酒在墙上,我瓶啤酒在墙上。 我不知道该改变什么来解决这个问题。是否创建另一个while部分? 如果你能给他们一个提示,这样我就可以自己解决它,那也很酷!因为我知道我的实际歌曲输出是在第一个if部分,但我不知道我应该在哪

  • 原文地址:https://cesiumjs.org/tutorials/cesium-and-webpack/ Cesium 和 Webpack Webpack是非常强大非常流行的JavaScript 模块打包工具。它可以让开发人员以一种简单直观的 require 方式去加载各种页面需要的文件,极大的方便了开源人员对代码和资源文件进行结构化设计。当编译的时候,它会跟踪代码依赖性,把所有的模型打包到

  • 问题内容: 我一直在学习redis和node.js。我有两个问题,找不到令人满意的答案。 我的第一个问题是关于在node.js中重用Redis客户端。我找到了这个问题和答案:如何在socket.io中重用Redis连接,但还不足以让我满意。 现在,如果我在连接事件中创建redis客户端,它将为每个连接生成。因此,如果我有2万个并发用户,那么将有2万个Redis客户端。 如果我将其放在连接事件之外,