testing Spring-Security - spring-security

I have several Controllers in my Spring-Boot (1.1.4.RELEASE)/ Spring-Security application that I would like to run some integration tests on. However, I don't know how to make the request so that the authentication is handled.
Here is my test:
#ContextConfiguration(classes = OFAC, loader = SpringApplicationContextLoader)
#Transactional
#WebAppConfiguration
#IntegrationTest
class AdminControllerIntegrationTest extends Specification {
def adminUrl = "http://localhost:9001/admin"
#Autowired
private AdminController adminController;
def "test retrieving users from db table"() {
def model = Mock(Model)
RestTemplate restTemplate = new TestRestTemplate()
when:
def result = restTemplate.getForEntity(adminUrl, String.class, model)
then:
result != null
}
Here is my security configuration:
#Configuration
#EnableWebMvcSecurity
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {
#Autowired
private CustomUserDetailsService customUserDetailsService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers( "/" ).permitAll()
.antMatchers( "/resources/**" ).permitAll()
.antMatchers( "/css/**" ).permitAll()
.antMatchers( "/libs/**" ).permitAll();
http
.formLogin().failureUrl( "/login?error" )
.defaultSuccessUrl( "/" )
.loginPage( "/login" )
.permitAll()
.and()
.logout().logoutRequestMatcher( new AntPathRequestMatcher( "/logout" ) ).logoutSuccessUrl( "/" )
.permitAll();
http
.sessionManagement()
.maximumSessions( 1 )
.expiredUrl( "/login?expired" )
.maxSessionsPreventsLogin( true )
.and()
.sessionCreationPolicy( SessionCreationPolicy.IF_REQUIRED )
.invalidSessionUrl( "/" );
http
.authorizeRequests().anyRequest().authenticated();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
PasswordEncoder encoder = new BCryptPasswordEncoder();
auth.userDetailsService( customUserDetailsService ).passwordEncoder( encoder );
}
When I debug that code,the result I get is the login html. I believe this means the authentication failed (and since I haven't defined the user /password anywhere) and my request is being redirected to the login page.
I looked for a good way to run Integration Tests against like this but haven't found a good solution. If anyone has any examples on how to handle this, I hope you would help

I think to do that kind of test you have no choice but to POST to the login form and extract the session cookie, so you can send it with the request you actually need to test. Something like this:
private String loginAndGrabCookie() {
ResponseEntity<String> page = serverRunning.getForString("/sparklr2/login.jsp");
String cookie = page.getHeaders().getFirst("Set-Cookie");
Matcher matcher = Pattern.compile("(?s).*name=\"_csrf\".*?value=\"([^\"]+).*").matcher(page.getBody());
MultiValueMap<String, String> formData;
formData = new LinkedMultiValueMap<String, String>();
formData.add("j_username", "marissa");
formData.add("j_password", "koala");
if (matcher.matches()) {
formData.add("_csrf", matcher.group(1));
}
String location = "/sparklr2/login.do";
HttpHeaders headers = new HttpHeaders();
headers.set("Cookie", cookie);
headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));
ResponseEntity<Void> result = serverRunning.postForStatus(location, headers , formData);
assertEquals(HttpStatus.FOUND, result.getStatusCode());
cookie = result.getHeaders().getFirst("Set-Cookie");
assertNotNull("Expected cookie in " + result.getHeaders(), cookie);
return cookie;
}
(Taken from https://github.com/spring-projects/spring-security-oauth/blob/master/samples/oauth2/sparklr/src/test/java/org/springframework/security/oauth2/provider/AuthorizationCodeProviderTests.java#L381.)

Related

H2 access denied

#Configuration
#EnableWebSecurity
#RequiredArgsConstructor
public class SecurityConfiguration {
private final JwtAuthenticationFilter jwtAuthFilter;
private final AuthenticationProvider authenticationProvider;
#Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.headers()
.frameOptions().disable()
.and()
.csrf().disable()
.authorizeHttpRequests()
.requestMatchers("/h2/**").permitAll()
.requestMatchers("/api/v1/auth/**").permitAll()
.anyRequest().authenticated()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authenticationProvider(authenticationProvider)
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
I have this config class. I placed .requestMatchers("/h2/**").permitAll() in the code but when I visit the http://localhost:8080/h2 I take:
Access to localhost was denied
the JwtAuthenticationFilter:
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtService jwtService;
private final UserDetailsService userDetailsService;
#Override
protected void doFilterInternal(
#NonNull HttpServletRequest request,
#NonNull HttpServletResponse response,
#NonNull FilterChain filterChain
) throws ServletException, IOException {
final String authHeader = request.getHeader("Authorization");
final String jwt;
final String userEmail;
if (authHeader == null ||!authHeader.startsWith("Bearer ")) {
filterChain.doFilter(request, response);
return;
}
jwt = authHeader.substring(7);
userEmail = jwtService.extractUsername(jwt);
if (userEmail != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.userDetailsService.loadUserByUsername(userEmail);
if (jwtService.isTokenValid(jwt, userDetails)) {
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
userDetails,
null,
userDetails.getAuthorities()
);
authToken.setDetails(
new WebAuthenticationDetailsSource().buildDetails(request)
);
SecurityContextHolder.getContext().setAuthentication(authToken);
}
}
filterChain.doFilter(request, response);
}
}
The doFilterInternal method is the main method of the filter. It checks if the incoming request has an "Authorization" header with a JWT starting with "Bearer ", and if so, extracts the user email from the JWT using the JwtService and loads the user details using the UserDetailsService. If the JWT is valid and the user details are successfully loaded, an Authentication object is created and set in the SecurityContextHolder. The filter chain is then continued with the filterChain.doFilter(request, response) call.

SpringSecurity using memory authentication don't returns error 403 in http put method

I don't receive the error 403 in http "put" method using SpringSecurity in memory authentication. The method returned 200 when it should return 403.
The same code using http "post" method works normally.
Note the exemple:
The Websecurity configuration:
#Configuration
public class WebSecutiryConfigurer extends WebSecurityConfigurerAdapter {
#Override
#Bean
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
#Override
#Bean
protected UserDetailsService userDetailsService() {
return super.userDetailsService();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().passwordEncoder(passwordEncoder()).withUser("11111111111")
.password(passwordEncoder().encode("minhasenha")).roles("Administrador").and().withUser("22222222222")
.password(passwordEncoder().encode("minhasenha")).roles("Consulta");
}
}
This is my ResourceServerConfigurerAdapter:
#Configuration
public class ResourceServerConfigurer extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/v1/cnaes").hasAnyRole("Administrador", "Alteracao", "Consulta")
.antMatchers(HttpMethod.POST, "/v1/cnaes").hasRole("Administrador")
.antMatchers(HttpMethod.DELETE, "/v1/cnaes").hasRole("Administrador")
.antMatchers(HttpMethod.PUT, "/v1/cnaes/delete").hasRole("Administrador")
.antMatchers(HttpMethod.PUT, "/v1/cnaes").hasRole("Administrador")
.and()
.anonymous().disable()
.exceptionHandling();
}
}
This is my method in a test class:
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class CnaeTeste {
#LocalServerPort
private int port;
private String urlGeracaoToken = "http://localhost:8088/oauth/token";
private String oauthTokenPerfilAdministrador;
private String oauthTokenPerfilConsulta;
#Before
public void setup() {
RestAssured.baseURI = "http://localhost:5555/mysystem/v1/cnaes";
}
#Before
public void autenticarPerfilAdministrador() {
Response response = RestAssured.given().auth().basic("usuario-bearer", "omissospj-pwd-bearer")
.formParam("scope", "intranet").formParam("username", "07068684718").formParam("password", "minhasenha")
.formParam("grant_type", "password").when().post(this.urlGeracaoToken);
this.oauthTokenPerfilAdministrador = response.jsonPath().get("access_token");
}
#Before
public void autenticarPerfilConsulta() {
Response response = RestAssured.given().auth().basic("usuario-bearer", "omissospj-pwd-bearer")
.formParam("scope", "intranet").formParam("username", "22222222222").formParam("password", "minhasenha")
.formParam("grant_type", "password").when().post(this.urlGeracaoToken);
this.oauthTokenPerfilConsulta = response.jsonPath().get("access_token");
}
#Test
public void falhaAtualizarQuandoUsuarioPerfilAlteracaoStatusCode403() throws Exception {
// insert
Cnae cnae = new Cnae(0L, "2222222", "CNAE de Teste - Criada - Perfil Administrador", false);
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
String json = ow.writeValueAsString(cnae);
Response responseInclusao = RestAssured.given()
.headers("Authorization", "Bearer " + this.oauthTokenPerfilAdministrador, "Content-Type",
ContentType.JSON, "Accept", ContentType.JSON)
.body(json).when().post();
Assertions.assertThat(responseInclusao.getStatusCode()).isEqualTo(201);
// update
String stringResponse = responseInclusao.getBody().asString();
JSONObject jsonObject = new JSONObject(stringResponse);
String idCadastrado = jsonObject.getString("id");
Long idAtualizado = Long.parseLong(idCadastrado);
cnae = new Cnae(idAtualizado, "2222222", "CNAE de Teste - Atualizada - Perfil Alteração", false);
ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
json = ow.writeValueAsString(cnae);
Response responseAlteracao = RestAssured.given().headers("Authorization",
"Bearer " + this.oauthTokenPerfilConsulta, "Content-Type", ContentType.JSON, "Accept", ContentType.JSON)
.body(json).when().put("/" + idCadastrado);
Assertions.assertThat(responseAlteracao.getStatusCode()).isEqualTo(403);
// delete
Response responseExcluir = RestAssured.given()
.headers("Authorization", "Bearer " + this.oauthTokenPerfilAdministrador, "Content-Type",
ContentType.JSON, "Accept", ContentType.JSON)
.when().delete("/" + idCadastrado).then().extract().response();
Assertions.assertThat(responseExcluir.getStatusCode()).isEqualTo(200);
}
}
I'm receive the 200 status code, when I expect to receive 403:
Assertions.assertThat(responseAlteracao.getStatusCode()).isEqualTo(403);
Any suggestion?
Is it also failing for delete, or only put?
Your put is directed to the url http://localhost:5555/mysystem/v1/cnaes/idCadastrado
but you only match for /v1/cnaes :
.antMatchers(HttpMethod.PUT, "/v1/cnaes").hasRole("Administrador")
Maybe you need to ensure that other requests be authenticated:
.antMatchers(HttpMethod.PUT, "/v1/cnaes/**").authenticated() or
.antMatchers(HttpMethod.PUT, "/v1/cnaes/**").hasRole("Administrador") or
.anyRequest().hasRole("Administrador") (place at the end after adding all other antMatchers)
It should still fail if there is no mapping in your controller to /v1/cnaes/:id, but I cannot see your controller entry points in the code you provided. I imagine that if the entry point exists, with the security level of #PreAuthorize("permitAll"), then you are successfully invoking it.

Authorization and TestRestTemplate

I'm using a default Spring login form and REST API for other data. Sessions are enabled and used.
All urls (except /login form ) are protected.
So how to test the protected #RestController methods using TestRestTemplate? (I could make an additional request to /api/login to get Cookie and then generate and add Headers, but there is no REST endpoint for login, only a form-base authencation).
Also, is the #WithMockUser annotation only for MockMvc (and can't be used with TestRestTemplate)?
Steps
Clone spring security example repo git clone https://github.com/spring-guides/gs-securing-web.git
Added RestControllerIT
Added csrf().disable() to WebSecurityConfig. This test will not pass if csrf enabled
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
public class RestControllerIT {
#Autowired
TestRestTemplate testRestTemplate;
#LocalServerPort
int localPort;
#Test
public void test(){
String securedUrl = "http://localhost:" + localPort + "/hello";
String loginUrl = "http://localhost:" + localPort + "/login";
String username = "user";
String password = "password";
MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
form.set("username", username);
form.set("password", password);
ResponseEntity<String> loginResponse = testRestTemplate.postForEntity(
loginUrl,
new HttpEntity<>(form, new HttpHeaders()),
String.class);
String cookie = loginResponse.getHeaders().get("Set-Cookie").get(0);
HttpHeaders headers = new HttpHeaders();
headers.add("Cookie", cookie);
ResponseEntity<String> responseFromSecuredEndPoint = testRestTemplate.exchange(securedUrl, HttpMethod.GET, new HttpEntity<>(headers), String.class);
assertEquals(responseFromSecuredEndPoint.getStatusCode(), HttpStatus.OK);
assertTrue(responseFromSecuredEndPoint.getBody().contains("Hello World!"));
}
}
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
#Bean
#Override
public UserDetailsService userDetailsService() {
UserDetails user =
User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
}

spring security mapping for wildcards

Using Spring-Boot 1.1.17, Spring-MVC with Spring-Security:
I have several subdomains that I want to to allow unauthenticated users (Visitors) access to. For example:
mysite.com/customerA
mysite.com/customerB
If a invalid customer site is attempted, then my controller would either throw an exception or redirect back to / (mysite.com/) Naturally other parts of the domain (mysite.com/customerA/myaccount) will require login.
I haven't really figured out how to do this with spring security and spring-mvc. Here is what I am attempting so far:
#Configuration
#EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private CustomUserDetailsService customUserDetailsService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterAfter(new CSRFTokenGeneratorFilter(), CsrfFilter.class)
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers( "/**/" ).permitAll()
.antMatchers("/login").permitAll()
.antMatchers("/wizard").permitAll()
.antMatchers("/menu").permitAll()
.antMatchers("/error").permitAll()
.antMatchers("/resources/**").permitAll()
.antMatchers("/css/**").permitAll()
.antMatchers("/js/**").permitAll()
.antMatchers("/fonts/**").permitAll()
.antMatchers("/libs/**").permitAll();
http
.formLogin()
.loginPage("/loginPage")
.permitAll()
.loginProcessingUrl("/login")
.failureUrl("/login?error")
.defaultSuccessUrl("/?tab=success")
.and()
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/")
.permitAll()
.and()
.csrf();
http
.sessionManagement()
.maximumSessions(1)
.expiredUrl("/login?expired")
.maxSessionsPreventsLogin(true)
.and()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.invalidSessionUrl("/");
http
.authorizeRequests().anyRequest().authenticated();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
PasswordEncoder encoder = new BCryptPasswordEncoder();
auth.userDetailsService( customUserDetailsService ).passwordEncoder( encoder );
}
#Override
public void configure(WebSecurity security){
security.ignoring().antMatchers("/css/**","/fonts/**","/libs/**");
}
}
And my homepage controller:
#Controller
#RequestMapping("/{officeName}/")
public class HomeController {
private AuthenticatedUser getVisitor(#PathVariable String officeName) {
.. do something with the office if found, redirect otherwise
if (!StringUtils.isEmpty(officeName)) {
Office office = officeService.findByName( officeName );
return office.getUrl();
}
return "/";
}
When I try to access that url, I get the following errors:
o.s.web.servlet.DispatcherServlet : DispatcherServlet with name 'dispatcherServlet' processing GET request for [/customerA/]
s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /customerA/
s.w.s.m.m.a.RequestMappingHandlerMapping : Did not find handler method for [/customerA/]
o.s.w.s.handler.SimpleUrlHandlerMapping : Matching patterns for request [/customerA/] are [/**]
o.s.w.s.handler.SimpleUrlHandlerMapping : URI Template variables for request [/customerA/] are {}
o.s.w.s.handler.SimpleUrlHandlerMapping : Mapping [/customerA/] to HandlerExecutionChain with handler [org.springframework.web.servlet.resource.ResourceHttpRequestHandler#2f295527] and 1 interceptor
o.s.web.servlet.DispatcherServlet : Last-Modified value for [/customerA/] is: -1
o.s.w.s.r.ResourceHttpRequestHandler : Trying relative path [customerA] against base location: ServletContext resource [/]
o.s.w.s.r.ResourceHttpRequestHandler : Trying relative path [customerA] against base location: class path resource [META-INF/resources/]
o.s.w.s.r.ResourceHttpRequestHandler : Trying relative path [customerA] against base location: class path resource [resources/]
o.s.w.s.r.ResourceHttpRequestHandler : Trying relative path [customerA] against base location: class path resource [static/]
o.s.w.s.r.ResourceHttpRequestHandler : Trying relative path [customerA] against base location: class path resource [public/]
o.s.w.s.r.ResourceHttpRequestHandler : No matching resource found - returning 404
I tried adding this ServletRegistrationBean:
#Bean
public ServletRegistrationBean dispatcherRegistration(DispatcherServlet dispatcherServlet) {
ServletRegistrationBean registration = new ServletRegistrationBean( dispatcherServlet );
registration.addUrlMappings("/", "/testCustomer/*" );
for ( Office office : officeService.findAllActiveOffices() ) {
registration.addUrlMappings( office.getUrl() + "/*" );
}
return registration;
}
But this would seem to only work if the application knows of the customer at startup, not dynamically in the case of customer signup.
Is there a way to configure this to handle these types of wildcards?
You can try with a configuration like the following:
#Configuration
#EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService _userService;
#Autowired
private PasswordEncoder _passwordEncoder;
/**
* Defines the password encoder used by Spring security during the
* authentication procedure.
*/
#Bean
public PasswordEncoder passwordEncoder() {
// default strength = 10
return new BCryptPasswordEncoder();
}
/**
* Sets security configurations for the authentication manager
*/
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
auth
.userDetailsService(_userService)
.passwordEncoder(_passwordEncoder);
return;
}
/**
* Configures where Spring Security will be disabled (security = none).
* From spring reference: "Typically the requests that are registered [here]
* should be that of only static resources. For requests that are dynamic,
* consider mapping the request to allow all users instead."
*/
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(
"/css/**",
"/js/**",
"/fonts/**",
"/resources/**",
"/libs/**");
return;
}
/**
* Sets security configurations in the HttpSecurity object.
*/
#Override
protected void configure(HttpSecurity http) throws Exception {
// Set security configurations
http
.authorizeRequests()
// the following urls are allowed for any user (no authentication)
.antMatchers(
"/",
"/login",
"/menu")
.permitAll()
// any other url must be authenticated
.anyRequest().authenticated()
.and()
// define the login page url
.formLogin()
.loginPage("/login")
.permitAll()
.and()
// define the logout url
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login?logout")
.permitAll();
return;
} // method configure
} // class WebSecurityConfig
Adding your personal configurations... You can try to add the following controller:
#Controller
public class HomeController {
#RequestMapping("/{officeName}/")
public AuthenticatedUser getVisitor(#PathVariable String officeName) {
// .. do something with the office if found, redirect otherwise
if (!StringUtils.isEmpty(officeName)) {
Office office = officeService.findByName( officeName );
return office.getUrl();
}
return "/";
}
}
If the user is correctly authenticated he should access the url at the officeName.

spring security jdbc throws null pointer

I am trying to use Spring-Security 4.0.0.M1 with Spring-Boot 1.0.2.RELEASE with H2 and Spring-data-jpa.1.5.2. I am able to create a user in the SecurityConfig.configure method, but when I extract this out to its own class, I get a nullpointer exception. I step into JdbcDaoSupport.java and see that the getJdbcTemplate() returns a null jdbcTemplate.
Here is my config:
#Configuration
#EnableWebMvcSecurity
#EnableGlobalMethodSecurity(prePostEnabled = false)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private DataSource dataSource;
#Autowired
UserService userService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers( "/resources/**" ).permitAll()
.antMatchers( "/css/**" ).permitAll();
http
.formLogin().failureUrl( "/login?error" )
.defaultSuccessUrl( "/" )
.loginPage( "/login" )
.permitAll()
.and()
.logout().logoutRequestMatcher( new AntPathRequestMatcher( "/logout" ) ).logoutSuccessUrl( "/login" )
.permitAll();
http
.authorizeRequests().anyRequest().authenticated();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
.dataSource( dataSource );
}
#Bean
#Override
public AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManagerBean();
}
}
My main configuration class has the datasource defined, which I know to work:
#Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder().setType( EmbeddedDatabaseType.H2 ).setName( "ofac" )
.addScript( "classpath:h2.sql" ).build();
}
I have a User Service for adding users as such:
#Component
public class UserService {
#Autowired
private AuthenticationManagerBuilder authenticationManagerBuilder;
#Autowired
private javax.sql.DataSource dataSource;
#PostConstruct()
public void initUsers() throws Exception {
addNewUser( "admin", "password", "ADMIN" );
}
public void addNewUser(String username, String plainPassword, String role) {
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.add( new SimpleGrantedAuthority( role ) );
PasswordEncoder encoder = new BCryptPasswordEncoder();
UserDetails hashedUser = new User( username, encoder.encode( plainPassword ), authorities );
JdbcUserDetailsManager userDetailsService = (JdbcUserDetailsManager) authenticationManagerBuilder.getDefaultUserDetailsService();
try {
if ( userDetailsService.userExists( hashedUser.getUsername() ) ) {
userDetailsService.deleteUser( hashedUser.getUsername() );
}
// and finally, create the user
userDetailsService.createUser( hashedUser );
} catch ( Exception ex ) {
ex.printStackTrace();
}
}
}
I have a breakpoint on the UserService.initUsers and when the line:
authenticationManagerBuilder.jdbcAuthentication().getUserDetailsService().userExists( hashedUser.getUsername() )
is invoked, I can see that authenticationManagerBuilder.jdbcAuthentication() returns a null jdbcTemplate. All the online documentation seems to indicate this would work, but it does not seem to wire up everything as I am expecting.
Does anyone know what might be wrong?
UPDATE:
I changed the project so I no longer have the SecurityConfig, but instead to have a:
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
#Configuration
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers( "/resources/**" ).permitAll()
.antMatchers( "/css/**" ).permitAll();
http
.formLogin().failureUrl( "/login?error" )
.defaultSuccessUrl( "/" )
.loginPage( "/login" )
.permitAll()
.and()
.logout().logoutRequestMatcher( new AntPathRequestMatcher( "/logout" ) ).logoutSuccessUrl( "/login" )
.permitAll();
http
.authorizeRequests().anyRequest().authenticated();
}
}
and a:
#Order(Ordered.HIGHEST_PRECEDENCE)
#Configuration
public class AuthenticationSecurity extends GlobalAuthenticationConfigurerAdapter {
#Autowired
private DataSource dataSource;
#Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
.dataSource( dataSource );
}
}
But in my UserService, I get a null userDetailsService here:
JdbcUserDetailsManager userDetailsService = (JdbcUserDetailsManager) authenticationManagerBuilder.getDefaultUserDetailsService();
I have not figured out how to actually create a user after startup. I thought it was with a UserDetailsService, but that doesn't provide the functionality. I thought maybe a JdbcUserDetailsManager is needed, but so far I haven't been able to wire one up that works.
The AuthenticationManagerBuilder may not have been fully initialized when it is injected into your object. Spring Security uses various markers to signal the initialization order, e.g. you could try extending GlobalAuthenticationConfigurerAdapter like in the method security sample.

Resources