Spring Security 4带有第三方身份验证令牌

时间:2015-11-18 18:01:07

标签: spring-mvc authentication spring-security token openam

我已经对此进行了大量的研究,并且有大量的例子,但我对这些选择感到不知所措,但我已经将一些代码放在一起以做我想做的事。

我有一个Apache Load Balancer,它会将我重定向到我们的OpenAM 10的登录页面。当我转到https://portal.mydomain.com/myapp时,我被重定向到: https://sso.mydomain.net:9443/sso/UI/Login?module=AGMAuth&goto=https%3A%2F%2Fvmlb.mydomain.net%3A443%2Fmyapp

这是我的登录页面,我被要求输入用户名和密码,然后我将一个看起来像(AQIC5wM2LY4Sfcyl9raxhA-xBE14_4QBbkjXi-rFn43PMpc。 AAJTSQACMDE。)的令牌带回一个cookie。从前端,我可以从cookie获取令牌,我可以将它添加到我的后端的每个调用的请求头,这是一个SpringMVC RESTful后端。

仅仅是一个FYI,我知道如何调用OpenAM RESTful api,传入该令牌并获取用户名和其他一些信息。角色不会保留在OpenAM中。如果在我的RESTful Web服务的后端,我使用令牌调用OpenAM ...如果我没有收回任何数据,那么我想回到我的自定义身份验证登录页面:https://sso.mydomain.net:9443/sso/UI/Login?module=AGMAuth&goto=https%3A%2F%2Fvmlb.mydomain.net%3A443%2Fmyapp < / p>

以下是我的安全网址之一的控制器:

@RequestMapping(value = "/trialId/{trialId}", method = RequestMethod.GET, headers = "Accept=application/json")
public @ResponseBody TrialEntity getTrialById(@PathVariable("trialId") long trialId)
{
    Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    System.out.println("TrialController: getTrialById: principal");

    UserAccountEntity user = null;
    if (principal instanceof UserAccountEntity)
    {
        user = ((UserAccountEntity) principal);
    }

    TrialEntity trialEntity = service.getById(trialId);
    System.out.println("TrialController: retrieveTrial: trialEntity=" + trialEntity);
    return trialEntity;
}

我是否需要让每个安全的URL尝试获取主体?

现在这是我的spring-security.XML安全文件。它可能不正确,但它是我开始的地方:

<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd">

<http realm="Protected API" 
    use-expressions="true"                     
    create-session="stateless" 
    entry-point-ref="unauthorizedEntryPoint" 
    authentication-manager-ref="restAuthenticationManager">

    <custom-filter ref="authenticationTokenProcessingFilter" position="FORM_LOGIN_FILTER" />
     <intercept-url pattern="/corelabs" access="permitAll" />
    <intercept-url pattern="/sponsors" access="permitAll" />
    <intercept-url pattern="/trials/trialId/**" access="hasRole('trialAdmin')" />
    <intercept-url pattern="/subjects" access="hasRole('siteSender') and hasRole('trialManager')" />
</http>

<authentication-manager>
  <authentication-provider ref="customAuthenticationProvider"/>
</authentication-manager>   

 <beans:bean id="customUserDetailsService" class="com.agmednet.server.security.CustomUserDetailsService" />

</beans:beans>

现在这里是后端的一些安全代码。这是返回数据库以根据用户名获取用户详细信息的代码,我还可以为该用户加载角色。我从Spring Security 4的一个例子中得到了这个。

@Service("customUserDetailsService")
@Transactional
public class CustomUserDetailsService implements UserDetailsService
{
private static final Log logger = LogFactory.getLog(CustomUserDetailsService.class);

@Autowired
private UserAccountDao userAccountDao;

@Transactional(readOnly = true)
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
{
    System.out.println("CustomUserDetailsService: username : " + username);
    UserAccountEntity userAccountEntity = userAccountDao.getByUsername(username);
    System.out.println("CustomUserDetailsService: userAccountEntity : " + userAccountEntity);
    if (userAccountEntity == null)
    {
        System.out.println("CustomUserDetailsService: userAccountEntity not found");
        throw new UsernameNotFoundException("Username not found");
    }

    System.out.println("CustomUserDetailsService: START: springframework.user");
    // this "User" object is: org.springframework.security.core.userdetails.User
    User user = new User(userAccountEntity.getUsername(), userAccountEntity.getPassword(), true, true, true, true,
        getGrantedAuthorities(userAccountEntity));

    System.out.println("CustomUserDetailsService: FINISH: springframework.user = " + user);
    return user;
}

private List<GrantedAuthority> getGrantedAuthorities(UserAccountEntity userAccountEntity)
{
    System.out.println("getGrantedAuthorities: START");
    List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();

    for (UserRoleEntity userRoleEntity : userAccountEntity.getUserRoleList())
    {
        System.out.println("getGrantedAuthorities: UserRoleEntity : " + userRoleEntity);
        authorities.add(new SimpleGrantedAuthority("ROLE_" + userRoleEntity.getUserRoleName()));
    }
    System.out.print("authorities :" + authorities);
    return authorities;
}

}

这是另一段安全代码,我不确定这是否对我有用。因为在这种情况下,我真的在看预身份验证策略,我不确定它们中是否真的适用于这种情况。我也看到我可以实现RequestHeaderFilter,但我也不确定它是如何适应的。

public class CustomAuthenticationProvider implements AuthenticationProvider
{
@Autowired
private CustomUserDetailsService userService;

public Authentication authenticate(Authentication authentication) throws AuthenticationException
{
    String username = authentication.getName();
    String password = (String) authentication.getCredentials();

    UserDetails user = userService.loadUserByUsername(username);

    if (user == null || !user.getUsername().equalsIgnoreCase(username))
    {
        throw new BadCredentialsException("Username not found.");
    }

    if (!password.equals(user.getPassword()))
    {
        throw new BadCredentialsException("Wrong password.");
    }

    Collection<? extends GrantedAuthority> authorities = user.getAuthorities();

    return new UsernamePasswordAuthenticationToken(user, password, authorities);
}

public boolean supports(Class<?> arg0)
{
    return true;
}

}

所以,我正在提取一些代码并尝试根据其他人如何使用工作解决方案的许多细微变化来理解这一切是如何工作的。 同样,我有一个来自第三方API并放入cookie的令牌。所以,我正在考虑那些对我来说绝对有意义的记忆场景......除了当令牌无效,到期或不存在时,我会被重定向到第三方登录页面。我以为我看到了一个给定URL的自定义登录表单的示例,因此如果身份验证无效(令牌不存在或无效),那么我们就没有被授权并被发送回那个可行的自定义登录URL对我来说。

基于我已添加的内容,我应该能够在将令牌传递给OpenAM之后从令牌中获取用户名...但我是否需要某种类型的requestheader过滤器才能获得它...然后使用用于加载userdetails和角色的用户名并将其放在SecurityContext中?

我对所有这些Spring Security管道只是一个noobie,所以对这个特定设置的任何帮助都会非常有帮助。顺便说一下,我不介意使用XML进行弹簧安全配置。如果我需要添加我的web.xml文件,我也可以这样做,但请假设我确实正确设置了我的web.xml。谢谢!

更新: 我有一个单元测试,看起来像:

@Test
public void testMockGetById() throws Exception
{
    MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.get(BASE_URL + "/trialId/149");
    this.mockMvc.perform(requestBuilder).andDo(print()).andExpect(status().isOk());
}

基于下面建议的SiteMinder示例。我现在正在寻找名为&#34; openam_token&#34;的请求标头。而不是&#34; SM_USER&#34;我已经在没有令牌的情况下对此进行了测试,并且我得到了500错误,即没有令牌。

所以,现在我需要改变我的单元测试,在请求头中添加一个令牌。此令牌将返回有权访问此URL的正确用户。第二个测试是拥有来自不同用户的令牌,该用户无法访问此URL。如果我的测试条件有效,我认为这是一个胜利。

1 个答案:

答案 0 :(得分:1)

Siteminder身份验证以类似的方式工作,在负载均衡器(Apache)上设置请求标头。我建议查看如何使用spring security设置siteminder的示例。请参阅this和春季文档here

不要认为您需要CustomAuthenticationProvider,因为在请求到达您的其他API之前正在处理身份验证。