I've started with the following file to config URLs and protected paths using Spring Security and OAuth2:
#EnableResourceServer
#RestController
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter
{
#RequestMapping("/publica")
public String publico() {
return "Pagina Publica";
}
#RequestMapping("/privada")
public String privada() {
return "Pagina Privada";
}
#RequestMapping("/admin")
public String admin() {
return "Pagina Administrador";
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().antMatchers("/oauth/token", "/oauth/authorize**", "/publica").permitAll();
http
.requestMatchers().antMatchers("/privada")
.and().authorizeRequests()
.antMatchers("/privada").access("hasRole('USER')")
.and().requestMatchers().antMatchers("/admin")
.and().authorizeRequests()
.antMatchers("/admin").access("hasRole('ADMIN')");
}
}
This works fine. If I try to access /privada in postman it returns a 401.
However, for the app I'm planning to build from this I figured it would be better to organise URLs in their own controllers (e.g. FundsController, UsersController, ProductsController etc)
So, as a basic example from the above I'm moving the path mapping methods out into BasicController:
#RestController
public class BasicController
{
#RequestMapping("/publica")
public String publico() {
return "Pagina Publica";
}
#RequestMapping("/privada")
public String privada() {
return "Pagina Privada";
}
#RequestMapping("/admin")
public String admin() {
return "Pagina Administrador";
}
}
But leaving the security stuff in the ResourceServerConfiguration:
#EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter
{
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().antMatchers("/oauth/token", "/oauth/authorize**", "/publica").permitAll();
http
.requestMatchers().antMatchers("/privada")
.and().authorizeRequests()
.antMatchers("/privada").access("hasRole('USER')")
.and().requestMatchers().antMatchers("/admin")
.and().authorizeRequests()
.antMatchers("/admin").access("hasRole('ADMIN')");
}
}
But now when I restart the app (in-memory access tokens destroyed) then go to /privada it returns Pagina Privada which is Spanish I think for "Private page" :) There was no access token required anyway, which is not what I wanted. It should return a 401 as it did before when it was all within the same class. Where have I gone wrong?
Add
#Configuration
#EnableWebSecurity
annotations to your ResourceServerConfiguration class and
extend WebSecurityConfigurerAdapter instead of ResourceServerConfigurerAdapter
You need to have below in the configure method you override
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/context"))
.antMatchers("/context/**").fullyAuthenticated();
Related
I have a legacy application in which I have added Spring Web MVC libraries in order to expose a new Rest API.
I am struggling integrating spring-security in order to intercept the incoming requests. I have set up a security configuration class
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests().anyRequest().authenticated().and().httpBasic();
}
}
and a security application initializer
public class SecurityWebApplicationInitializer extends
AbstractSecurityWebApplicationInitializer {
}
following relevant guides.
Using debugger I verified that during initializing my configuration class is loaded. My problem is that my requests are not intercepted as expected.
Since you're already using Spring MVC, go to your class that initializes your application. If you're using Java Config, it most likely extends AbstractAnnotationConfigDispatcherServletInitializer.
Add your SecurityConfig to its "root config classes":
public class MySpringMmvcInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
...
#Override
protected abstract Class<?>[] getRootConfigClasses() {
return new Class[] { ..., SecurityConfig.class};
}
}
I think you forgot the #configuration annotation, try this
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests().anyRequest().authenticated().and().httpBasic();
}
}
I have a project with Spring security and Oauth2.
On the resource server I have the following configuration:
#Configuration
public class SecurityConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(final HttpSecurity http) throws Exception {
http.antMatcher("/**")
.authorizeRequests().antMatchers("/info", "/health", "/h2-console/**").permitAll()
.anyRequest().authenticated()
.and().headers().frameOptions().disable();
}
}
I have the following extractors:
#Component
public class InsurancePrincipalExtractor implements PrincipalExtractor {
#Override
public Object extractPrincipal(Map<String, Object> map) {
return map.get("username");
}
}
#Component
public class InsuranceAuthoritiesExtractor implements AuthoritiesExtractor {
#Override
public List<GrantedAuthority> extractAuthorities(Map<String, Object> map) {
//Logic
}
I set the user-info-uri: http://localhost:8081/uaa/v1/me
The problem is that it does not hit my extractor methods at runtime, so nothing happens. As I know I just need to annotate it with the #Component and the Spring boot and will use it auto.
UPDATE:
Solution founded.
I had to add this to my configuration as well:
#Bean
protected ResourceServerTokenServices resourceServerTokenServices(ResourceServerProperties sso,
OAuth2ClientContext oauth2ClientContext,
UserInfoRestTemplateFactory restTemplateFactory) {
UserInfoTokenServices services = new UserInfoTokenServices(sso.getUserInfoUri(), sso.getClientId());
services.setRestTemplate(restTemplateFactory.getUserInfoRestTemplate());
services.setTokenType(sso.getTokenType());
return services;
}
I'm developing a springboot application with spring security.
I'm trying to make my custom authentication filter reading some properties from the application.properties file without success.
I've read this other question which is similar but within a different context (not related to spring security filters). The reason for the failure makes sense to me but I've tried the way suggested with the DelegatingFilterProxy but without success (to be fair, I didn't really get the meaning of the part added to the Application class). The other solution does not fit my case as I don't have any onStartup method to override.
Here is the code I'm using:
public class JWTAuthenticationFilter extends
AbstractAuthenticationProcessingFilter {
#Value("${app.jwtSecret}")
public String SECRET2;
Almost the same code, in a controller class, works fine:
#RestController
#RequestMapping("/api")
#CrossOrigin
#EnableAutoConfiguration
public class UsersController {
#Value("${app.jwtSecret}")
public String SECRET2;
But I can't make it work in the filter. I'm using springboot 2.0.3.
Any suggestion? Is the DelegatingFilterProxy the right approach in this situation? In that case, any example/article I could follow?
Thanks,
Michele.
UPDATE:
to fully answer to the first comment, the filter is called by the following class:
#EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
#Autowired
private LdapAuthenticationProvider ldapAuthenticationProvider;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable().authorizeRequests()
.antMatchers(HttpMethod.POST, "/api/secureLogin").permitAll()
.antMatchers(HttpMethod.GET, "/api").permitAll()
.antMatchers("/api/**").authenticated()
.and()
.addFilterBefore(new JWTAuthenticationFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class)
.addFilter(new JWTAuthorizationFilter(authenticationManager()))
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(ldapAuthenticationProvider);
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
No need to use #Value in filter class:
public class JWTAuthenticationFilter extends
AbstractAuthenticationProcessingFilter {
private String secret;
//... setter for secret
But inject the secret in the config class:
#EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
#Value("${app.jwtSecret}")
public String secret;
//...
#Override
protected void configure(HttpSecurity http) throws Exception {
JWTAuthorizationFilter jwtFilter = new JWTAuthorizationFilter(authenticationManager());
//set secret
//...
}
I have implemented an application with combination Spring Boot and Angular 4. I put all Angular files under /resources/static directory:
static directory
Then I added to Spring Security classes:
#Configuration
#EnableWebMvc
#ComponentScan("com.inventory")
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/static/**")
.addResourceLocations("classpath:/resources/static/");
}
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index.html");
}
}
and:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordencoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
.antMatchers("/").permitAll()
.anyRequest().authenticated();
}
and it seem that everythings should work. Unfortunately whenever I run my app it throws exception:
There was an unexpected error (type=Internal Server Error, status=500).
Could not resolve view with name 'index.html' in servlet with name 'dispatcherServlet'.
Of course I tried diffrent solution like adding this:
#Controller
public class ViewController {
#RequestMapping(value = "/#/")
public String index() {
return "forward:/index.html";
}
#RequestMapping(value = "/")
public String home() {
return "forward:/index.html";
}
}
But nothing works. Does anyone has a clue what else can I do?
When using Spring boot normally you don't have to configure resource handler manually, spring boot will automatically load contents from the following loc:
/static
/public
/resources
/META-INF/resources
see spring boot guides on loading static contents
Here's a problem: I would like to protect a URI until authorized with some third-party OAuth2. Based on http://docs.spring.io/spring-security/oauth/apidocs/org/springframework/security/oauth2/config/annotation/web/configuration/EnableOAuth2Client.html, I have these:
#Configuration
#EnableOAuth2Client
public class OAuth2Client extends OAuth2ClientConfiguration {
#Bean
public Filter filter() {
DelegatingFilterProxy f = new DelegatingFilterProxy();
f.setTargetBeanName("oauth2ClientContextFilter");
return f;
}
#Resource
#Qualifier("oauth2ClientContextFilter")
private OAuth2ClientContextFilter oauth2ClientContextFilter;
#Resource
#Qualifier("accessTokenRequest")
private AccessTokenRequest accessTokenRequest;
#Bean
public OAuth2ProtectedResourceDetails remote() {
AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
details.setUserAuthorizationUri("http://localhost2/oauth/authorize");
return details;
}
#Bean
public OAuth2RestOperations restTemplate() {
return new OAuth2RestTemplate(remote(), new DefaultOAuth2ClientContext(
accessTokenRequest));
}
}
And
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
// Empty for now...
}
And finally
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
super.configure(auth);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers().antMatchers("/protectedUri").and()
.authorizeRequests().requestMatchers()
.hasRole("#oauth2.hasScope('read')");
}
}
But this gives:
java.lang.IllegalStateException: At least one mapping is required
(i.e. authorizeRequests().anyRequest.authenticated())
I've tried quite a few combinations of the HttpSecurity builder to no avail - any help, or is this approach entirely off base?
is this approach entirely off base?
Yes. An empty ResourceServerConfigurerAdapter isn't going to help you. You should configure the protected paths, e.g.
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/protectedUri").authenticated();
}
(and leave out your WebSecurityConfigurerAdapter).
The client configuration at the top looks wrong too, but it's not relevant to the protected resource (start a new question if you want to know how to configure the client).