I'm trying to add in spring-security-oauth to an existing app with spring-security. I'm using Java config.
I have an existing amended filter chain in place (with some custom filters added in) but requests to '/oauth/token' aren't using it, but are using the 'default' filter chain. How can i get access to the filter chain that's securing the oauth endpoints so that i can use the custom filters there also or can I wire in the OAuth endpoint(s) into the existing setup?
there is indeed a slightly smoother way using the interface AuthorizationServerConfigurer.
You can stick to the annotation #EnableAuthorizationServer and implement above interface in your configuration file. This will enable you to alter the oauth2-filter-chain by doing something like this:
#Configuration
#EnableWebSecurity
#EnableAuthorizationServer
public class SecurityConfig extends WebSecurityConfigurerAdapter
implements AuthorizationServerConfigurer
// some configuration ...
public void configure(AuthorizationServerSecurityConfigurer oauthSecurity) throws Exception {
oauthSecurity.addTokenEndpointAuthenticationFilter(new YourFilter());
}
// more configuration ...
}
In contrast to the addFilterXYX-methods of HttpSecurity you have no fine-grained influence here where the filter will be positioned in the filter chain. Any filter added by addTokenEndpointAuthenticationFilter will be inserted before the BasicAuthenticationFilter.
If you need to control the position of you filter in a more detailed way you could create a bean extending AuthorizationServerConfigurerAdapter instead of using the annotation #EnableAuthorizationServer. I did not try that but I guess you could then extend AuthorizationServerSecurityConfigurationlike systemfreund suggested without having to specify #Order(-1) because only your custom configuration gets imported. Probably you would also have to #Import AuthorizationServerEndpointsConfigurationlike it is done in the convenience annotation #EnableAuthorizationServer.
It's probably not the best way to do it, but I did not manage to find a better approach. The idea is to provide a custom AuthorizationServerSecurityConfiguration instance and override the default instance which is #Imported via #EnableAuthorizationServer. We just need to make sure to add an #Order annotation with higher precendence than the default configuration:
#EnableAuthorizationServer
#Import(CustomSecurityConfig.class)
public class Application {
}
#Configuration
#Order(-1)
public class CustomSecurityConfig extends AuthorizationServerSecurityConfiguration {
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http); // do the default configuration first
http
.addFilterBefore(new MyFilter(), ...);
}
}
Related
I just read answer from the another question What is the use of #EnableWebSecurity in Spring?, but i couldn't understand why we need to add #EnableWebSecurity annotation at all.
Even I remove the #EnableWebSecurity from the configuration, my application still works.
Let's assume that we are going to implement either JWT based (rest api) or simply login based mvc application. For the following configuration what i am missing?
#Component
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Bean
public UserDetailsService userDetailsService() {
return new MyCustomUserDetailsService();
}
#Bean
public PasswsordEncoder passwsordEncoder() {
return new BrcyptPasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// for the jwt authentication add jwt filter etc ..
// for the login based, override default login page, error page etc..
}
}
If you are not using spring-boot but just a pure spring project , you definitely need to add #EnableWebSecurity in order to enable spring-security.
But if you are using spring-boot 2.0 +, you do not need to add it by yourself because the spring-boot auto configuration will automatically do it for you if you forget to do so. Under the cover , it is done by the WebSecurityEnablerConfiguration which its javadoc also states this behaviour as follows:
If there is a bean of type WebSecurityConfigurerAdapter, this adds the
#EnableWebSecurity annotation. This will
make sure that the annotation is present with default security
auto-configuration and also if the user adds custom security and
forgets to add the annotation.
I'd like have a set of services that can be used with "Client Credential" (for machine to machine) and with OAuth2 Single Sign On for the regular webapp (which is served by the same application).
I tried setting both #EnableOAuth2Sso and #EnableResourceServer; I expected to have the app "try" the token based and then fall back to SSO redirect in case it doesn't find any and the user does not have a session.
Each config works fine on its own (with a:
#Bean
public RemoteTokenServices ...
for #EnableResourceServer to configure the "CheckTokenEndpointUrl").
But as soon as I try with both I get:
APPLICATION FAILED TO START
Description:
Method springSecurityFilterChain in org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration required a single bean, but 2 were found:
- userInfoTokenServices: defined by method 'userInfoTokenServices' in class path resource [org/springframework/boot/autoconfigure/security/oauth2/resource/ResourceServerTokenServicesConfiguration$RemoteTokenServicesConfiguration$UserInfoTokenServicesConfiguration.class]
- remoteTokenServices: defined by method 'remoteTokenServices' in class path resource [my/CustomWebSecurityConfigurerAdapter.class]
In your spring boot application class use the #EnableOAuth2Sso annotation and in the configuration class use #EnableResourceServer annotation and in this class define the endpoints to be used with access tokens.
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/user") //end point that needs access token in header
.antMatcher("/info") //end point that needs access token in header
.authorizeRequests().anyRequest().authenticated();
}
}
For more information refer the link
We are using OAuth2 for securing our REST endpoints. Nearly all of our endpoints require authentication. We have couple of public endpoints. We configure spring security using #EnableWebSecurity. All the public endpoints are explicitly listed in the configuration (see "publicpath_x" in the example below). Instead of explicitly adding each new public enpodint in the configuration, it would be much easier to have a custom annotation, e.g. #PublicAccess which will designate each public endpoint. Is it possible to configure that endpoints annotated with this annotation will be considered as public, i.e. no authentication will be required? We don't want to designate public endpoints in path (e.g. all public endpoints path will start/end with "/public").
Security configuration:
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
//...
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatchers("publicpath1", "publicpath2").permitAll() //...
}
}
Example public REST controller with custom annotation:
#RestController
public class PublicController1 {
#PublicAccess //our custom annotation
#RequestMapping(value = "publicpath1", method = RequestMethod.GET)
public void publicEndpoint1() {
//...
}
}
I was trying the following classes with no success.
javax.servlet.Filter
org.springframework.web.servlet.handler.HandlerInterceptorAdapter
You can use the #PreAuthorize Annotations as method security
Detail see here
I am trying to add an interceptor to a simple Spring-boot-mongodb-rest app, as can be seen here : http://spring.io/guides/gs/accessing-mongodb-data-rest/, in order to perform certain actions after the default rest handler is invoked. Here is my MongoRepository, whose CRUD operation is called upon a POST request to the server:
#RepositoryRestResource(collectionResourceRel = "reminder", path = "reminder")
public interface ReminderRepository extends MongoRepository<Reminder, String> {
List<Reminder> findBySendee(#Param("sendee") String sendee);
}
I am trying to register an interceptor for all HTTP requests by extending the WebMvcConfigurerAdapter class like this:
#Configuration
#ComponentScan
public class RemindxWebConfig extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry registry){
registry.addInterceptor(new RemindxInterceptor());
}
}
As mentioned in the spring boot docs, I have not added the #EnableWebMvc annotation to this. While running the application, the addInterceptors function does get called and adds the interceptor. However, the given interceptor is not called after the POST handler is invoked. I am unable to figure out a way to have spring use this RemindxWebConfig for all MongoRepository http requests. Any inputs are appreciated.
At the moment I try to figure out how Spring Security evaluates the given URL, expression and annotations. So far it seems like it always checks the entries from security-context.xml first. And if that's a denyAll it will simply stop further processing of the request.
Maybe I forgot to set some configuration option, but (in my eyes) it's not possible to build a nice whitelist using Spring Security's annotations (like #Secured, #PermitAll, etc.).
What I want is basically to annotate the methods inside a #Controller for allowing access. For example:
#Controller
#RequestMapping("/test")
public MyController {
#RequestMapping("")
public void tryToGetSomething() {
// no security annotation -> denyAll
}
#RequestMapping("/public")
#PermitAll
public void tryToGetSomethingPublic() {
// this will always have access allowed
}
#RequestMapping("/admin")
#Secured({"ROLE_ADMIN"})
public void tryToGetSomethingReallyImportant() {
// this can only be accessed by admins
}
}
The main reason for this approach is: Security ;-). It's always possible to forget some annotations while writing code. And with this method such a mistake won't affect security of sensitive data.
So my question is: How can I achieve this?
You can try to use security pointcuts in conjuction with annotations:
<global-method-security pre-post-annotations="enabled">
<!-- Disable access to all controller methods -->
<protect-pointcut expression="execution(* com.mycompany.controllers.*Controller.*(..))"
access="ROLE_THAT_DOES_NOT_EXIST"/>
</global-method-security>
#Controller
#RequestMapping("/test")
public MyController {
#RequestMapping("")
public void tryToGetSomething() {
// pointcut rule -> no one has ROLE_THAT_DOES_NOT_EXIST -> no one can call this code
}
#RequestMapping("/public")
#PreAuthorized("permitAll")
public void tryToGetSomethingPublic() {
// annotations take precedence over pointcuts, so anyone can call this code due to #PreAuthorized("permitAll") rule
}
}
See corresponding entry from the official documentation. Maybe you can use denyAll instead of ROLE_THAT_DOES_NOT_EXIST.
Hope this helps.
I tried to achieve the same, but the problem is that method security level applies to every method called through AOP. If you deny access by default, you will will have to annotate pretty much everything :)
With URL based security, you can proceed by whitelist:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.anyRequest().denyAll();
}
The obvious drawback, unfortunately, is that every URL has to be authorized here, creating a kind of dependency magnet. But maybe it is a good thing to centralize URL path mapping ?