使用外部身份验证源时如何在 Spring 引导中模拟身份验证
How can I mock Authentication in a Spring Boot when using an Exernal Authentication Source
我有一个 Spring 基于启动的应用程序,我们使用来自外部提供商的 ISAM 身份验证。
我有一个 rest/json 端点 /actuator/health
return 不同的数据,具体取决于用户是否经过身份验证。
如何在单元测试期间模拟身份验证以确保我的配置正确?
在 setup()
中,我尝试手动设置令牌,并将 AuthorizationService 覆盖为 return true。
@Before
public void setUp() throws Exception
{
mockMvc = webAppContextSetup(wac).apply(springSecurity()).build();
List roles = Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"));
UsernamePasswordAuthenticationToken auth =
new UsernamePasswordAuthenticationToken("dave", "secret",
roles);
if (!auth.isAuthenticated()) { fail("NOT AUTHENTICATED!"); }
SecurityContextHolder.getContext().setAuthentication(auth);
//fake logged in
when(authorizationService.isCurrentUserAuthorized(anyString(),
anyString(),
ArgumentMatchers.any(ResourceType.class),
ArgumentMatchers.any(ActionType.class)))
.thenReturn(true);
}
然而,当我运行
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (!auth.isAuthenticated()) { fail("NOT AUTHENTICATED!"); }
UsernamePasswordAuthenticationToken authToken =
(UsernamePasswordAuthenticationToken)auth;
mockMvc.perform(get("/health_secure")
.principal(auth)
.header("Authorization", "Bearer " + token))
.andDo(print())
.andExpect(status().isOk())
.andExpect(forwardedUrl("/actuator/health"));
我得到:
"error":"invalid_token","error_description":"Cannot convert access token to JSON"
很好的答案 here。由于spring security 不会创建request-scoped bean,所以你自己创建一个然后注入到你需要的地方。这使您有机会自己模拟它。
是这样的吗?:
@Service
@RequiredArgsConstructor
public class UserService {
public Principal getPrincipal() {
return SecurityContextHolder.getContext().getAuthentication();
}
public Optional<String> getCurrentLogin() {
Principal principal = getPrincipal();
if (principal == null)
return Optional.empty();
return Optional.ofNullable(principal.getName());
}
}
我的应用程序使用 ISAM/OAuth2
进行身份验证
我希望只是覆盖 AuthenticationManager
或 OAuth2AuthenticationManager
我找到了一个稍微低级的解决方案。
注意: 我希望看到 AuthenticationManager
级别的解决方案。
我不得不重写 ResourceServerTokenServices bean 来模拟我的假授权数据。
我在 @Before
方法中添加了 setAuth()
方法。
//"constants" for fake auth values
private static final String user = "MyUser";
private static final String token = "MyTokenString";
//TokenServices to validate/convert ISAM Bearer Token
@MockBean ResourceServerTokenServices tokenServices;
private Authentication setAuth() throws Exception
{
UsernamePasswordAuthenticationToken auth =
new UsernamePasswordAuthenticationToken(user, token,
Collections.emptyList());
if (!auth.isAuthenticated()) { fail("NOT AUTHENTICATED!"); }
SecurityContextHolder.getContext().setAuthentication(auth);
DefaultOAuth2AccessToken mockTokenImpl = new DefaultOAuth2AccessToken(user);
mockTokenImpl.setScope(Collections.singleton("authenticate:applications"));
mockTokenImpl.setTokenType("Bearer");
when(tokenServices.readAccessToken(anyString())).thenReturn(mockTokenImpl);
OAuth2Authentication oa2Auth = mock(OAuth2Authentication.class);
when(oa2Auth.getPrincipal()).thenReturn(user);
when(oa2Auth.getCredentials()).thenReturn(token);
when(oa2Auth.getUserAuthentication()).thenReturn(auth);
when(oa2Auth.isAuthenticated()).thenReturn(true);
OAuth2Request oa2Req = mock(OAuth2Request.class);
when(oa2Auth.getOAuth2Request()).thenReturn(oa2Req);
when(tokenServices.loadAuthentication(anyString())).thenReturn(oa2Auth);
return auth;
}
此方法配置 tokenServices
以获取所有必要的信息来伪造它通过 authenticate()
使用 Springs OAuth2AuthenticationManager class.
我有一个 Spring 基于启动的应用程序,我们使用来自外部提供商的 ISAM 身份验证。
我有一个 rest/json 端点 /actuator/health
return 不同的数据,具体取决于用户是否经过身份验证。
如何在单元测试期间模拟身份验证以确保我的配置正确?
在 setup()
中,我尝试手动设置令牌,并将 AuthorizationService 覆盖为 return true。
@Before
public void setUp() throws Exception
{
mockMvc = webAppContextSetup(wac).apply(springSecurity()).build();
List roles = Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"));
UsernamePasswordAuthenticationToken auth =
new UsernamePasswordAuthenticationToken("dave", "secret",
roles);
if (!auth.isAuthenticated()) { fail("NOT AUTHENTICATED!"); }
SecurityContextHolder.getContext().setAuthentication(auth);
//fake logged in
when(authorizationService.isCurrentUserAuthorized(anyString(),
anyString(),
ArgumentMatchers.any(ResourceType.class),
ArgumentMatchers.any(ActionType.class)))
.thenReturn(true);
}
然而,当我运行
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (!auth.isAuthenticated()) { fail("NOT AUTHENTICATED!"); }
UsernamePasswordAuthenticationToken authToken =
(UsernamePasswordAuthenticationToken)auth;
mockMvc.perform(get("/health_secure")
.principal(auth)
.header("Authorization", "Bearer " + token))
.andDo(print())
.andExpect(status().isOk())
.andExpect(forwardedUrl("/actuator/health"));
我得到:
"error":"invalid_token","error_description":"Cannot convert access token to JSON"
很好的答案 here。由于spring security 不会创建request-scoped bean,所以你自己创建一个然后注入到你需要的地方。这使您有机会自己模拟它。
是这样的吗?:
@Service
@RequiredArgsConstructor
public class UserService {
public Principal getPrincipal() {
return SecurityContextHolder.getContext().getAuthentication();
}
public Optional<String> getCurrentLogin() {
Principal principal = getPrincipal();
if (principal == null)
return Optional.empty();
return Optional.ofNullable(principal.getName());
}
}
我的应用程序使用 ISAM/OAuth2
进行身份验证我希望只是覆盖 AuthenticationManager
或 OAuth2AuthenticationManager
我找到了一个稍微低级的解决方案。
注意: 我希望看到 AuthenticationManager
级别的解决方案。
我不得不重写 ResourceServerTokenServices bean 来模拟我的假授权数据。
我在 @Before
方法中添加了 setAuth()
方法。
//"constants" for fake auth values
private static final String user = "MyUser";
private static final String token = "MyTokenString";
//TokenServices to validate/convert ISAM Bearer Token
@MockBean ResourceServerTokenServices tokenServices;
private Authentication setAuth() throws Exception
{
UsernamePasswordAuthenticationToken auth =
new UsernamePasswordAuthenticationToken(user, token,
Collections.emptyList());
if (!auth.isAuthenticated()) { fail("NOT AUTHENTICATED!"); }
SecurityContextHolder.getContext().setAuthentication(auth);
DefaultOAuth2AccessToken mockTokenImpl = new DefaultOAuth2AccessToken(user);
mockTokenImpl.setScope(Collections.singleton("authenticate:applications"));
mockTokenImpl.setTokenType("Bearer");
when(tokenServices.readAccessToken(anyString())).thenReturn(mockTokenImpl);
OAuth2Authentication oa2Auth = mock(OAuth2Authentication.class);
when(oa2Auth.getPrincipal()).thenReturn(user);
when(oa2Auth.getCredentials()).thenReturn(token);
when(oa2Auth.getUserAuthentication()).thenReturn(auth);
when(oa2Auth.isAuthenticated()).thenReturn(true);
OAuth2Request oa2Req = mock(OAuth2Request.class);
when(oa2Auth.getOAuth2Request()).thenReturn(oa2Req);
when(tokenServices.loadAuthentication(anyString())).thenReturn(oa2Auth);
return auth;
}
此方法配置 tokenServices
以获取所有必要的信息来伪造它通过 authenticate()
使用 Springs OAuth2AuthenticationManager class.