【发布时间】:2016-02-20 14:29:01
【问题描述】:
我已经对此进行了大量研究,并且有大量示例,但我对选择感到不知所措,但我已经将一些代码放在一起来做我想做的事情。
我有一个 Apache 负载均衡器,它会将我重定向到 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
这是我的登录页面,我被要求输入用户名和密码,然后我在 cookie 中取回了一个类似于 (AQIC5wM2LY4Sfcyl9raxhA-xBE14_4QBbkjXi-rFn43PMpc.AAJTSQACMDE.) 的令牌。从前端,我可以从 cookie 中获取令牌,我可以将它添加到请求标头中,以便每次调用后端是 SpringMVC RESTful 后端。
仅供参考,我知道如何调用 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
这是我的一个安全 URL 的控制器:
@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 后,我应该能够从令牌中获取用户名……但我是否需要某种请求头过滤器才能首先获取它……然后使用加载用户详细信息和角色并将其放入 SecurityContext 的用户名?
我只是所有这些 Spring Security 管道的菜鸟,所以对这个特定设置的任何帮助都会非常有帮助。顺便说一句,我不介意将 XML 用于 spring 安全配置。如果我需要添加我的 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 示例。我现在正在寻找一个名为“openam_token”而不是“SM_USER”的请求标头
所以,现在我需要更改我的单元测试以在请求标头中添加一个令牌。此令牌将返回有权访问此 URL 的正确用户。第二个测试是拥有来自不同用户的令牌,该用户无权访问此 URL。如果我的测试条件有效,我会认为这是一场胜利。
【问题讨论】:
标签: spring-mvc authentication spring-security token openam