Migration to Spring Boot (Security) 2 from 1.x - spring

In a current migration of a project from Spring boot 1.X to 2.0.9 I am facing a hard time with the Spring Security module. In a first step I have to change the properties to access the datasources (to jdbc-url) and now that part seems to be working just fine, but now the security module seems to be not rightly attached.
So in properties I have tried to add the following:
spring.security.user.name=admin
spring.security.user.password=secret
But even if I comment it or dis-comment it, I face the same result, when I call the webservices, the dialog prompts asking for credentials:
The configuration of the authentication is the following:
class OAuth2Configuration extends AuthorizationServerConfigurerAdapter {
#Configuration
#EnableAuthorizationServer // [1]
#EnableGlobalMethodSecurity(prePostEnabled = true)
#EnableWebSecurity
protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {
#Autowired
private TokenStore tokenStore;
#Autowired
private DataSource oauthDataSource;
#Autowired
private PhrqlAuthenticationManager phrqlAuthenticationManager;
/**
* Config clientDetail storage
* #param endpoints
* #throws Exception
*/
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
endpoints.authenticationManager(phrqlAuthenticationManager);
endpoints.tokenStore(tokenStore);
// endpoints.tokenStore(tokenStore).pathMapping("/oauth/token", "/p/oauth/token");
}
#Override // [3]
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(oauthDataSource);
}
}
For some reason, I think that the autoconfig is not accessing to the name-pass, so then the client ask for credentials. Any help will be much appreciated. Thanks in advance!

Related

mockmvc unable to retrieve headers set by WebSecurityConfigurerAdapter

I created a commons library with the intent of injecting headers into the response of every API call. I updated the WebSecurityConfigurerAdaptor and wrote a mockmvc test case to test/assert those headers. However I observed that mockmvc is unable to find/assert those headers in the test even though WebSecurityConfigurerAdaptor injects those headers. Appreciate if you can share your perspective upon any issues you see with this approach.
Below is the WebSecurityConfigurerAdapter snippet:
#Slf4j
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SoaWebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
#Getter
#Setter
private RestTemplateBuilder restTemplateBuilder;
#Override
protected void configure(final HttpSecurity http) throws Exception {
// Disable caching
http.headers().cacheControl();
// default deny framing/embedding
http.headers().frameOptions().deny();
headerConfigurer(http.headers());
}
protected void headerConfigurer(HeadersConfigurer<HttpSecurity> headersConfigurer) {
log.info("SOACustomWebSecurityConfig: header config invoked");
headersConfigurer.addHeaderWriter(
// (HeaderWriter) new StaticHeadersWriter(Arrays.asList(new Header("Access-control-Allow-Origin", "*"),
// new Header("strict-transport-security", "max-age=31536000; includeSubdomains"))));
(HeaderWriter) new StaticHeadersWriter("strict-transport-security",
"max-age=31536000; includeSubdomains"));
}
Below is the corresponding test case:
private void testHeadersPresence(String resourceURl, String origin) throws Exception {
mvc.perform(options(resourceURl).header("Access-Control-Request-Method", "GET").header("Origin", origin))
.andExpect(header().string("strict-transport-security", "max-age=31536000; includeSubdomains"));
}
The test case fails with the error:
Expected "max-age=31536000; includeSubdomains" but was [null]
Note: the change is being made in a common library (a separate repo) which is included in multiple spring boot services (that offers APIs)
Any insight is much appreciated. Thank you

How to include custom security interceptor in spring boot test

I want to do some end-to-end test for spring boot rest-api application. To achieve this im using spring mock mvc. But i can't get the 200 response because the rest api is using custom security interceptor to validate the token in request. Instead i keep getting 401 as a response. How to include this token validation in my test?
I've tried several configuration by including #ContextConfiguration(classes = {WebMvcConfig.class}) in my test class. WebMvcConfig is configuration class to register the interceptor.
This is my test file
#AutoConfigureMockMvc
#RunWith(SpringRunner.class)
#SpringBootTest(classes = VeripalServiceApplication.class)
#TestPropertySource(locations="classpath:test.properties")
#Transactional
public class VeripalTextConfigurationTest {
#Autowired
private MockMvc mockMvc;
#Test
public void happpyPath_thenReturns200() throws Exception {
String jsonBody = "some json body";
String endPoint = "/end_point_to_my_api";
HttpHeaders headers = new HttpHeaders();
headers.add("token", "this_is_my_token");
headers.setContentType(aplication/json);
/** Hit the API */
mockMvc.perform(post(endPoint)
.headers(httpHeaders)
.content(jsonBody)
)
.andExpect(status().isOk()).andDo(print());
}
}
And this is the #Configuration
#Configuration
#EnableScheduling
public class WebMvcConfig extends WebMvcConfigurerAdapter {
#Autowired
private ConsumerService consumerService;
#Autowired
private EndpointService endpointService;
#Autowired
private ConsumerConfigurationService consumerConfigurationService;
#Autowired
private AccessLimitService accessLimitService;
#Autowired
private ConfigurationHistoryService configurationHistoryService;
#Autowired
private LimitCarryOverService limitCarryOverService;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new Interceptor(consumerService, endpointService, consumerConfigurationService, accessLimitService, configurationHistoryService, limitCarryOverService));
}
}
And this is my Interceptor class
public class Interceptor implements HandlerInterceptor {
// some code here ...
}
you need to have a clear picture of request life-cycle in Servlet API and Spring Security framework.
This article might help you to understand this flow http://blog.florian-hopf.de/2017/08/spring-security.html
So, I'm pretty sure, you have an issue in authentication filters, thus you can resolve it in couple ways:
Disable security, for example by using #AutoConfigureMockMvc(secure = false)
Or you need to mock some places (AuthenticationProvider, UserDetailsService, etc) where you can provide Authentication object
Or, it also might help, try to play with #WithMockUser
.
Related posts:
Spring Test & Security: How to mock authentication?
V2: use IoC + Mockito, e.g. stub it for unit tests. I don't see how your code are written, so I believe a snippet below might help you.
// #Import({MyAuthCustomInterceptor.class}) // eq to #Component/#Service to create a bean
public class WebMvcConfig extends WebMvcConfigurerAdapter {
#Autowired
MyAuthCustomInterceptor interceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(interceptor);
}
}
public class VeripalTextConfigurationTest {
#MockBean
MyAuthCustomInterceptor interceptor;
#SetUp
public void setup(){
Mockito.when(interceptor.preHandle(...)).thenReturn(true);
}
}

Is #Order really needed in Spring Boot 2.0.4 OAuth server?

I have this little OAuth server class and I am using Spring Boot 2.0.4 and the spring-security-oauth2-autoconfigure 2.0.0.RELEASE dependency :
#RestController
#SpringBootApplication
#EnableAuthorizationServer
#Order(200) // really needed ?
public class MyOAuthServerApplication extends WebSecurityConfigurerAdapter {
#RequestMapping({ "/me" })
public Map<String, String> user(Principal principal) {
Map<String, String> map = new LinkedHashMap<>();
map.put("name", principal.getName());
return map;
}
#Configuration
#EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
// #formatter:off
http.antMatcher("/me").authorizeRequests().anyRequest().authenticated();
// #formatter:on
}
}
#Bean
#Override
public UserDetailsService userDetailsService() {
UserDetails mary =
User.withUsername("mary")
.password("{bcrypt}$2a$10$B3NUb0x.MYnSfx7WJItrvO/ymEQwLCKQNehmCuA8keL1uTyHizI0i")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(mary);
}
public static void main(String[] args) {
SpringApplication.run(MyOAuthServerApplication.class, args);
}
}
This seems to work well with and without the #Order(200) annotation.
So is this annotation really needed ?
The Order annotation is used to define the injection precedence.
Read more her: https://www.baeldung.com/spring-order
In your case it's because of the EnableResourceServer annotation. And you must keep the annotation.
From the doc:
The #EnableResourceServer annotation creates a security filter with
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER-1) by default, so by
moving the main application security to
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) we ensure that the
rule for "/me" takes precedence.
Please find the tutorial here: https://spring.io/guides/tutorials/spring-boot-oauth2/
You need it if you have another WebSecurityConfigurerAdapter configuration.
For example if you allow users to login via login form with a different UserDetailsService and so on. Then this should be tried before your oauth authentification and thus needs a lower order, for example #Order(199).
Another example would be different configuration for your API access.
If you don't have any other configuration, then you don't need to set the order.
Setting the order to 200 also seems to be an arbitrary value, that should simply be higher then the others and thus executed last.

AuthenticationSuccessEvent Listener for two spring applications connected through Shared Redis session

I am having two spring-boot application with shared session through Redis..
application-1 contains the login flow and application-2 uses the same session created on application-1,
Now i wanted to listen to the successful authentication on application-2.
Tried using InteractiveAuthenticationSuccessEvent listener as below ..
#EventListener({AuthenticationSuccessEvent.class, InteractiveAuthenticationSuccessEvent.class})
public void processAuthenticationSuccessEvent(AbstractAuthenticationEvent e) {
logger.info("Autenticación successful ....");
e.getAuthentication().getName();
}
Added the below code in securityConfig
#EnableWebSecurity
#Configuration
#Component
#Order
class SecurityConfig extends WebSecurityConfigurerAdapter {
.....
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationEventPublisher(authenticationEventPublisher());
}
#Bean
public DefaultAuthenticationEventPublisher authenticationEventPublisher() {
return new DefaultAuthenticationEventPublisher();
}
}
But 'InteractiveAuthenticationSuccessEvent' in application-2 is not triggered on authenticating on application-1..
Can someone guide me on this ?
I have used Redis PubSub to resolve my problem by listening to the Authentication Event from Application-1 to Application-2..

Configure SpringSecurity 4 with application.properties

I'm trying to add HTTP basic authentication into my springboot microservice.
When I use the "code" way described in Spring doc it works perfectly:
#RestController
public class Ping
{
#GetMapping("/ping")
public String ping()
{
return "pong";
}
}
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception
{
auth.inMemoryAuthentication()
.withUser("user").password("password")
.roles("USER");
}
}
But, if I want to use the properties way it seems that it's not possible or I'm doing something wrong:
security.basic.enabled = true
security.basic.path = /**
security.basic.realm = Spring
security.user.name = user
security.user.password = xxx
security.user.role = USER
security.sessions = always
Using this solution, only the resource http://localhost/env is secured, and /ping is not. It is possible to use only application.properties to configure a "simple" basic authentication to all the resources?

Resources