final class FilterComparator implements Comparator<Filter>,
Serializable {
private static final int INITIAL_ORDER = 100;
private static final int ORDER_STEP = 100;
private final Map<String, Integer> filterToOrder =
new HashMap<>();
FilterComparator() {
Step order =
new FilterComparator.Step(INITIAL_ORDER, ORDER_STEP);
put(ChannelProcessingFilter.class, order.next());
put(ConcurrentSessionFilter.class, order.next());
put(WebAsyncManagerIntegrationFilter.class, order.next());
put(SecurityContextPersistenceFilter.class, order.next());
put(HeaderWriterFilter.class, order.next());
put(CorsFilter.class, order.next());
put(CsrfFilter.class, order.next());
put(LogoutFilter.class, order.next());
// ……
public interface AccessDecisionVoter<S> {
int ACCESS_GRANTED = 1;
int ACCESS_ABSTAIN = 0;
int ACCESS_DENIED = -1;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final UserDetailsServiceImpl userDetailsService;
// ……
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/js/**", "/css/**", "/webjars/**").permitAll()
.antMatchers("/users/**").hasRole(Role.STAFF.name())
.antMatchers("/**").authenticated()
.and()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/success", true)
.failureUrl("/login?error=true").permitAll();
}
}
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final UserDetailsServiceImpl userDetailsService;
// ……
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/js/**", "/css/**", "/webjars/**").permitAll()
.antMatchers("/users/**").hasRole(Role.STAFF.name())
.antMatchers("/**").authenticated()
.and()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/success", true)
.failureUrl("/login?error=true").permitAll();
}
}
public FormLoginConfigurer() {
super(new UsernamePasswordAuthenticationFilter(),null);
usernameParameter("username");
passwordParameter("password");
}
public Authentication attemptAuthentication(
HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
// ……
String username = obtainUsername(request);
String password = obtainPassword(request);
if (username == null) {
username = "";
}
if (password == null) {
password = "";
}
username = username.trim();
UsernamePasswordAuthenticationToken authRequest =
new UsernamePasswordAuthenticationToken(username, password);
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
public Authentication attemptAuthentication(
HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
// ……
String username = obtainUsername(request);
String password = obtainPassword(request);
if (username == null) {
username = "";
}
if (password == null) {
password = "";
}
username = username.trim();
UsernamePasswordAuthenticationToken authRequest =
new UsernamePasswordAuthenticationToken(username, password);
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
// ……
for (AuthenticationProvider provider : getProviders()) {
if (!provider.supports(toTest)) {
continue;
}
// ……
try {
result = provider.authenticate(authentication);
if (result != null) {
copyDetails(authentication, result);
break;
}
}
// ……
protected final UserDetails retrieveUser(
String username, UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
// ……
try {
UserDetails loadedUser =
this.getUserDetailsService().loadUserByUsername(username);
if (loadedUser == null) {
// ……
}
return loadedUser;
}
// ……
}
@Service
@RequiredArgsConstructor
public class UserDetailsServiceImpl implements UserDetailsService {
private final UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
User user = userRepository.findByUsername(username)
.orElseThrow(
() -> new UsernameNotFoundException("username not found"));
return new org.springframework.security.core.userdetails.User(
user.getUsername(),
user.getPassword(),
createAuthorityList("ROLE_" + user.getRole().name()));
}
}
protected void additionalAuthenticationChecks(
UserDetails userDetails,
UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
// ……
String presentedPassword =
authentication.getCredentials().toString();
if (!passwordEncoder.matches(
presentedPassword, userDetails.getPassword())) {
// ……
throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials",
"Bad credentials"));
}
}
public class CustomPreAuthenticatedProcessingFilter extends
AbstractPreAuthenticatedProcessingFilter {
@Override
protected Object getPreAuthenticatedPrincipal(
HttpServletRequest request) {
return "";
}
@Override
protected Object getPreAuthenticatedCredentials(
HttpServletRequest request) {
String accessToken =
request.getHeader(HttpHeaders.AUTHORIZATION);
if (StringUtils.isEmpty(accessToken)
|| !accessToken.startsWith("Bearer ")) {
return "";
}
return accessToken.split(" ")[1];
}
}
public class CustomPreAuthenticatedProcessingFilter extends
AbstractPreAuthenticatedProcessingFilter {
@Override
protected Object getPreAuthenticatedPrincipal(
HttpServletRequest request) {
return "";
}
@Override
protected Object getPreAuthenticatedCredentials(
HttpServletRequest request) {
String accessToken =
request.getHeader(HttpHeaders.AUTHORIZATION);
if (StringUtils.isEmpty(accessToken)
|| !accessToken.startsWith("Bearer ")) {
return "";
}
return accessToken.split(" ")[1];
}
}
private void doAuthenticate(
HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
Authentication authResult;
Object principal = getPreAuthenticatedPrincipal(request);
Object credentials = getPreAuthenticatedCredentials(request);
// ……
try {
PreAuthenticatedAuthenticationToken authRequest =
new PreAuthenticatedAuthenticationToken(
principal, credentials);
authRequest.setDetails(
authenticationDetailsSource.buildDetails(request));
authResult = authenticationManager.authenticate(authRequest);
successfulAuthentication(request, response, authResult);
}
catch (AuthenticationException failed) {
// ……
}
}
private void doAuthenticate(
HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
Authentication authResult;
Object principal = getPreAuthenticatedPrincipal(request);
Object credentials = getPreAuthenticatedCredentials(request);
// ……
try {
PreAuthenticatedAuthenticationToken authRequest =
new PreAuthenticatedAuthenticationToken(
principal, credentials);
// ……
authResult = authenticationManager.authenticate(authRequest);
successfulAuthentication(request, response, authResult);
}
catch (AuthenticationException failed) {
// ……
}
}
public Authentication authenticate(Authentication auth)
throws AuthenticationException {
String accessToken = Optional.ofNullable(auth.getCredentials())
.map(Object::toString)
.orElse(null);
if (accessToken == null) {
throw new BadCredentialsException("access token not found.");
}
DecodedJWT decodedAccessToken = JWTUtils.decode(accessToken);
// ……
String username = decodedAccessToken.getClaim("username").asString();
UserDetails ud = userDetailsService.loadUserDetails(
new PreAuthenticatedAuthenticationToken(
username, auth.getCredentials());
return new PreAuthenticatedAuthenticationToken(
ud, authentication.getCredentials(), ud.getAuthorities());
}
public Authentication authenticate(Authentication auth)
throws AuthenticationException {
String accessToken = Optional.ofNullable(auth.getCredentials())
.map(Object::toString)
.orElse(null);
if (accessToken == null) {
throw new BadCredentialsException("access token not found.");
}
DecodedJWT decodedAccessToken = JWTUtils.decode(accessToken);
// ……
String username = decodedAccessToken.getClaim("username").asString();
UserDetails ud = userDetailsService.loadUserDetails(
new PreAuthenticatedAuthenticationToken(
username, auth.getCredentials());
return new PreAuthenticatedAuthenticationToken(
ud, authentication.getCredentials(), ud.getAuthorities());
}
public Authentication authenticate(Authentication auth)
throws AuthenticationException {
String accessToken = Optional.ofNullable(auth.getCredentials())
.map(Object::toString)
.orElse(null);
if (accessToken == null) {
throw new BadCredentialsException("access token not found.");
}
DecodedJWT decodedAccessToken = JWTUtils.decode(accessToken);
// …… JWT
String username = decodedAccessToken.getClaim("username").asString();
UserDetails ud = userDetailsService.loadUserDetails(
new PreAuthenticatedAuthenticationToken(
username, auth.getCredentials());
return new PreAuthenticatedAuthenticationToken(
ud, authentication.getCredentials(), ud.getAuthorities());
}
@Service
public class CustomAuthenticationUserDetailsService
implements AuthenticationUserDetailsService {
private final CustomUserDetailsService userDetailsService;
// ……
@Override
public UserDetails loadUserDetails(Authentication token)
throws UsernameNotFoundException {
String username = token.getPrincipal().toString();
String accessToken = token.getCredentials().toString();
return
Optional.ofNullable(
userDetailsService.loadUserByUsername(username))
.map(u ->
new CustomUserDetails(
((CustomUserDetails) u).getUser(), accessToken))
.orElseThrow(() ->
new UsernameNotFoundException("user not found"));
}
}
<dependencies>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
testCompile “org.springframework.security:spring-
security-test:5.1.1.RELEASE”
@BeforeEach
void beforeEach() {
mockMvc = MockMvcBuilders
.webAppContextSetup(context)
.apply(springSecurity())
.build();
}
@Test
void loginSuccess() throws Exception {
MvcResult result =
mockMvc
.perform(formLogin()
.user("ruchitate").password("password"))
.andReturn();
Assertions.assertThat(result.getResponse())
.extracting(
MockHttpServletResponse::getStatus,
MockHttpServletResponse::getRedirectedUrl)
.containsExactly(302, "/success");
}
@Test
void useWith200() throws Exception {
MvcResult result = mockMvc.perform(get("/users/{id}", 1)
.with(user("ruchitate").roles("STAFF")))
.andExpect(status().isOk())
.andReturn();
assertEquals(
"{"name":" ","username":"ruchitate",
"createdAt":"2018-10-01T00:00:00","lastSignInAt":null}",
result.getResponse().getContentAsString());
}
@Test
void useWith403ForAdmin() throws Exception {
mockMvc.perform(get("/users/{id}", 1)
.with(user("ruchitate").roles("ADMIN")))
.andExpect(status().isForbidden())
.andReturn();
}
@PreAuthorize("hasRole('ADMIN')")
public List<User> list() {
return userRepository.findAll();
}
@PreAuthorize("#role == 'ADMIN'")
public List<User> list(String role) {
return userRepository.findAll();
}
@PreAuthorize("#r.name == 'ruchitate'")
public List<User> list(@P("r") UserRequest request) {
return userRepository.findAll();
}
@PostAuthorize("returnObject != null &&
returnObject.username == 'ruchitate'")
public User get(Integer id) {
return userRepository.findById(id).orElse(null);
}
@PreFilter("filterObject.name.equals('ruchitate')")
public List<User> list(List<UserRequest> requests) {
List<String> usernameList = requests.stream()
.map(UserRequest::getName)
.collect(Collectors.toList());
return userRepository
.findAllByUsernameIn(usernameList);
}
@PostFilter("filterObject.username == 'ruchitate'")
public List<User> list() {
return userRepository.findAll();
}
Amazon Cognito使って認証したい?それならSpring Security使いましょう!
Amazon Cognito使って認証したい?それならSpring Security使いましょう!
Amazon Cognito使って認証したい?それならSpring Security使いましょう!
Amazon Cognito使って認証したい?それならSpring Security使いましょう!

Amazon Cognito使って認証したい?それならSpring Security使いましょう!

  • 13.
    final class FilterComparatorimplements Comparator<Filter>, Serializable { private static final int INITIAL_ORDER = 100; private static final int ORDER_STEP = 100; private final Map<String, Integer> filterToOrder = new HashMap<>(); FilterComparator() { Step order = new FilterComparator.Step(INITIAL_ORDER, ORDER_STEP); put(ChannelProcessingFilter.class, order.next()); put(ConcurrentSessionFilter.class, order.next()); put(WebAsyncManagerIntegrationFilter.class, order.next()); put(SecurityContextPersistenceFilter.class, order.next()); put(HeaderWriterFilter.class, order.next()); put(CorsFilter.class, order.next()); put(CsrfFilter.class, order.next()); put(LogoutFilter.class, order.next()); // ……
  • 26.
    public interface AccessDecisionVoter<S>{ int ACCESS_GRANTED = 1; int ACCESS_ABSTAIN = 0; int ACCESS_DENIED = -1;
  • 40.
    @Configuration @EnableWebSecurity public class WebSecurityConfigextends WebSecurityConfigurerAdapter { private final UserDetailsServiceImpl userDetailsService; // …… @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/js/**", "/css/**", "/webjars/**").permitAll() .antMatchers("/users/**").hasRole(Role.STAFF.name()) .antMatchers("/**").authenticated() .and() .formLogin() .loginPage("/login") .loginProcessingUrl("/login") .defaultSuccessUrl("/success", true) .failureUrl("/login?error=true").permitAll(); } }
  • 41.
    @Configuration @EnableWebSecurity public class WebSecurityConfigextends WebSecurityConfigurerAdapter { private final UserDetailsServiceImpl userDetailsService; // …… @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/js/**", "/css/**", "/webjars/**").permitAll() .antMatchers("/users/**").hasRole(Role.STAFF.name()) .antMatchers("/**").authenticated() .and() .formLogin() .loginPage("/login") .loginProcessingUrl("/login") .defaultSuccessUrl("/success", true) .failureUrl("/login?error=true").permitAll(); } }
  • 42.
    public FormLoginConfigurer() { super(newUsernamePasswordAuthenticationFilter(),null); usernameParameter("username"); passwordParameter("password"); }
  • 45.
    public Authentication attemptAuthentication( HttpServletRequestrequest, HttpServletResponse response) throws AuthenticationException { // …… String username = obtainUsername(request); String password = obtainPassword(request); if (username == null) { username = ""; } if (password == null) { password = ""; } username = username.trim(); UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password); setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); }
  • 46.
    public Authentication attemptAuthentication( HttpServletRequestrequest, HttpServletResponse response) throws AuthenticationException { // …… String username = obtainUsername(request); String password = obtainPassword(request); if (username == null) { username = ""; } if (password == null) { password = ""; } username = username.trim(); UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password); setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); }
  • 48.
    public Authentication authenticate(Authenticationauthentication) throws AuthenticationException { // …… for (AuthenticationProvider provider : getProviders()) { if (!provider.supports(toTest)) { continue; } // …… try { result = provider.authenticate(authentication); if (result != null) { copyDetails(authentication, result); break; } } // ……
  • 50.
    protected final UserDetailsretrieveUser( String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { // …… try { UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username); if (loadedUser == null) { // …… } return loadedUser; } // …… }
  • 51.
    @Service @RequiredArgsConstructor public class UserDetailsServiceImplimplements UserDetailsService { private final UserRepository userRepository; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userRepository.findByUsername(username) .orElseThrow( () -> new UsernameNotFoundException("username not found")); return new org.springframework.security.core.userdetails.User( user.getUsername(), user.getPassword(), createAuthorityList("ROLE_" + user.getRole().name())); } }
  • 52.
    protected void additionalAuthenticationChecks( UserDetailsuserDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { // …… String presentedPassword = authentication.getCredentials().toString(); if (!passwordEncoder.matches( presentedPassword, userDetails.getPassword())) { // …… throw new BadCredentialsException(messages.getMessage( "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); } }
  • 75.
    public class CustomPreAuthenticatedProcessingFilterextends AbstractPreAuthenticatedProcessingFilter { @Override protected Object getPreAuthenticatedPrincipal( HttpServletRequest request) { return ""; } @Override protected Object getPreAuthenticatedCredentials( HttpServletRequest request) { String accessToken = request.getHeader(HttpHeaders.AUTHORIZATION); if (StringUtils.isEmpty(accessToken) || !accessToken.startsWith("Bearer ")) { return ""; } return accessToken.split(" ")[1]; } }
  • 76.
    public class CustomPreAuthenticatedProcessingFilterextends AbstractPreAuthenticatedProcessingFilter { @Override protected Object getPreAuthenticatedPrincipal( HttpServletRequest request) { return ""; } @Override protected Object getPreAuthenticatedCredentials( HttpServletRequest request) { String accessToken = request.getHeader(HttpHeaders.AUTHORIZATION); if (StringUtils.isEmpty(accessToken) || !accessToken.startsWith("Bearer ")) { return ""; } return accessToken.split(" ")[1]; } }
  • 77.
    private void doAuthenticate( HttpServletRequestrequest, HttpServletResponse response) throws IOException, ServletException { Authentication authResult; Object principal = getPreAuthenticatedPrincipal(request); Object credentials = getPreAuthenticatedCredentials(request); // …… try { PreAuthenticatedAuthenticationToken authRequest = new PreAuthenticatedAuthenticationToken( principal, credentials); authRequest.setDetails( authenticationDetailsSource.buildDetails(request)); authResult = authenticationManager.authenticate(authRequest); successfulAuthentication(request, response, authResult); } catch (AuthenticationException failed) { // …… } }
  • 78.
    private void doAuthenticate( HttpServletRequestrequest, HttpServletResponse response) throws IOException, ServletException { Authentication authResult; Object principal = getPreAuthenticatedPrincipal(request); Object credentials = getPreAuthenticatedCredentials(request); // …… try { PreAuthenticatedAuthenticationToken authRequest = new PreAuthenticatedAuthenticationToken( principal, credentials); // …… authResult = authenticationManager.authenticate(authRequest); successfulAuthentication(request, response, authResult); } catch (AuthenticationException failed) { // …… } }
  • 81.
    public Authentication authenticate(Authenticationauth) throws AuthenticationException { String accessToken = Optional.ofNullable(auth.getCredentials()) .map(Object::toString) .orElse(null); if (accessToken == null) { throw new BadCredentialsException("access token not found."); } DecodedJWT decodedAccessToken = JWTUtils.decode(accessToken); // …… String username = decodedAccessToken.getClaim("username").asString(); UserDetails ud = userDetailsService.loadUserDetails( new PreAuthenticatedAuthenticationToken( username, auth.getCredentials()); return new PreAuthenticatedAuthenticationToken( ud, authentication.getCredentials(), ud.getAuthorities()); }
  • 82.
    public Authentication authenticate(Authenticationauth) throws AuthenticationException { String accessToken = Optional.ofNullable(auth.getCredentials()) .map(Object::toString) .orElse(null); if (accessToken == null) { throw new BadCredentialsException("access token not found."); } DecodedJWT decodedAccessToken = JWTUtils.decode(accessToken); // …… String username = decodedAccessToken.getClaim("username").asString(); UserDetails ud = userDetailsService.loadUserDetails( new PreAuthenticatedAuthenticationToken( username, auth.getCredentials()); return new PreAuthenticatedAuthenticationToken( ud, authentication.getCredentials(), ud.getAuthorities()); }
  • 83.
    public Authentication authenticate(Authenticationauth) throws AuthenticationException { String accessToken = Optional.ofNullable(auth.getCredentials()) .map(Object::toString) .orElse(null); if (accessToken == null) { throw new BadCredentialsException("access token not found."); } DecodedJWT decodedAccessToken = JWTUtils.decode(accessToken); // …… JWT String username = decodedAccessToken.getClaim("username").asString(); UserDetails ud = userDetailsService.loadUserDetails( new PreAuthenticatedAuthenticationToken( username, auth.getCredentials()); return new PreAuthenticatedAuthenticationToken( ud, authentication.getCredentials(), ud.getAuthorities()); }
  • 85.
    @Service public class CustomAuthenticationUserDetailsService implementsAuthenticationUserDetailsService { private final CustomUserDetailsService userDetailsService; // …… @Override public UserDetails loadUserDetails(Authentication token) throws UsernameNotFoundException { String username = token.getPrincipal().toString(); String accessToken = token.getCredentials().toString(); return Optional.ofNullable( userDetailsService.loadUserByUsername(username)) .map(u -> new CustomUserDetails( ((CustomUserDetails) u).getUser(), accessToken)) .orElseThrow(() -> new UsernameNotFoundException("user not found")); } }
  • 88.
  • 89.
    @BeforeEach void beforeEach() { mockMvc= MockMvcBuilders .webAppContextSetup(context) .apply(springSecurity()) .build(); }
  • 90.
    @Test void loginSuccess() throwsException { MvcResult result = mockMvc .perform(formLogin() .user("ruchitate").password("password")) .andReturn(); Assertions.assertThat(result.getResponse()) .extracting( MockHttpServletResponse::getStatus, MockHttpServletResponse::getRedirectedUrl) .containsExactly(302, "/success"); }
  • 91.
    @Test void useWith200() throwsException { MvcResult result = mockMvc.perform(get("/users/{id}", 1) .with(user("ruchitate").roles("STAFF"))) .andExpect(status().isOk()) .andReturn(); assertEquals( "{"name":" ","username":"ruchitate", "createdAt":"2018-10-01T00:00:00","lastSignInAt":null}", result.getResponse().getContentAsString()); }
  • 92.
    @Test void useWith403ForAdmin() throwsException { mockMvc.perform(get("/users/{id}", 1) .with(user("ruchitate").roles("ADMIN"))) .andExpect(status().isForbidden()) .andReturn(); }
  • 95.
    @PreAuthorize("hasRole('ADMIN')") public List<User> list(){ return userRepository.findAll(); } @PreAuthorize("#role == 'ADMIN'") public List<User> list(String role) { return userRepository.findAll(); } @PreAuthorize("#r.name == 'ruchitate'") public List<User> list(@P("r") UserRequest request) { return userRepository.findAll(); }
  • 96.
    @PostAuthorize("returnObject != null&& returnObject.username == 'ruchitate'") public User get(Integer id) { return userRepository.findById(id).orElse(null); }
  • 97.
    @PreFilter("filterObject.name.equals('ruchitate')") public List<User> list(List<UserRequest>requests) { List<String> usernameList = requests.stream() .map(UserRequest::getName) .collect(Collectors.toList()); return userRepository .findAllByUsernameIn(usernameList); }
  • 98.
    @PostFilter("filterObject.username == 'ruchitate'") publicList<User> list() { return userRepository.findAll(); }