Spring Security Method Without Login Form - spring

I want to just secure the method but not the end point( API) with #Secured. In the over ride method that extends GlobalMethodSecurityConfiguration i will have way to call the some dependent service if the user is allowed depending the on input passed in #Secured Annotation.
for example
#Secured("abc")
public void secureMethod(){
system.out.println("You are allowed)
}
The interceptor (that extends GlobalMethodSecurityConfiguration) method will check if the input to #Secured method has input as abc or something and then return access_denied to this method only. The input to method will be passed by calling service and can be injected at run time.
How i can do that w/o having login screen.

I'm not sure I fully got your question, but to disable the form-login including login/logout screens you would do this:
#Configuration
#EnableWebSecurity
public static class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity security) throws Exception
{
security.formLogin().disable();
}
}
Note: As you are using GlobalMethodSecurityConfiguration , you can try and nest this class INSIDE it.
So:
#Configuration
#EnableGlobalMethodSecurity
public class SecurityConfig extends GlobalMethodSecurityConfiguration {
// do whatever is needed here
#Configuration
public static class WebSecurityConfig extends
WebSecurityConfigurerAdapter { // nesting
#Override
protected void configure(HttpSecurity security) throws Exception
{
security.formLogin().disable();
}
}
}

Related

Spring Boot Security - Ant Matcher doesn't work

I am trying to get familiar with spring boot security, my API is a simple GET/POST to 127.0.0.1:8080/employee/
with a simple autoconfiguration like this.
#Configuration
public class SecurityConfig implements WebMvcConfigurer {
#Configuration
protected static class ApplicationSecurity extends WebSecurityConfigurerAdapter{
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user1").password("{noop}user1").authorities("USER").and()
.withUser("user2").password("{noop}user2").authorities("USER").and()
.withUser("admin").password("{noop}admin").authorities("ADMIN");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/employee/**").authorizeRequests().anyRequest().hasRole("ADMIN");
}
}
}
This always gives me 403 Forbidden.
Have tried this:-
antMatcher("/employee*"), works but for any user. Can I get some help in understanding how this pattern works, I just need to restrict "/employee" or "/employee/" or "/employee/1" to Admin.
Your current configuration will only restrict any paths under employee e.g. employee/1 but not /employee. Additionally you are not doing anything with the employee matcher as you go back to authorizeRequests, then configure anyRequest has a role ADMIN
To restrict employee and any path underneath it to ADMIN.
http.authorizeRequests().antMatchers("/employee**", "/employee/**").hasRole("ADMIN").httpBasic();
Using ** will capture directories in path.
See
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/util/AntPathMatcher.html
and
https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/util/matcher/AntPathRequestMatcher.html
Using a pattern value of /** or ** is treated as a universal match, which will match any request. Patterns which end with /** (and have no other wildcards) are optimized by using a substring match — a pattern of /aaa/** will match /aaa, /aaa/ and any sub-directories, such as /aaa/bbb/ccc.
I would also recommend testing your security configuration via the #WebMvcTest slice test
https://www.baeldung.com/spring-security-integration-tests
From the above a simple example would be,
#RunWith(SpringRunner.class)
#WebMvcTest(SecuredController.class)
public class SecuredControllerWebMvcIntegrationTest {
#Autowired
private MockMvc mvc;
// ... other methods
#WithMockUser(roles= {"admin"})
#Test
public void givenAuthRequestOnPrivateService_shouldSucceedWith200() throws Exception {
mvc.perform(get("/employee/1").contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
//Repeated for other Paths
}

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.

Disable Spring Boot Security #Secured at runtime [duplicate]

Is there a way I can disable the global method security using the boolean securityEnabled from my config.properties? Any other approach?
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled=true)
#PropertySource("classpath:config.properties")
public class SecurityConfig
extends WebSecurityConfigurerAdapter {
#Value("${securityconfig.enabled}")
private boolean securityEnabled;
...
}
The easiest way to do this is:
Extract method security to its own class
Remove the securedEnabled attribute entirely
Override the customMethodSecurityMetadataSource method and return the result based on the configured value.
For example:
#EnableWebSecurity
#Configuration
#PropertySource("classpath:config.properties")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
...
}
#EnableGlobalMethodSecurity
#Configuration
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
#Value("${securityconfig.enabled}")
private boolean securityEnabled;
protected MethodSecurityMetadataSource customMethodSecurityMetadataSource() {
return securityEnabled ? new SecuredAnnotationSecurityMetadataSource() : null;
}
}
I've managed this by defining a Spring "securityDisabled" profile and conditionally applying security config based off that. I'm using Spring Boot 2.0.2. I believe this should work if not using Spring Boot and in previous versions of Spring Boot, but I have not tested. It's possible some tweaks may be required to property and class names because I know in Spring 2.0 some of that changed.
// In application.properties
spring.profiles.include=securityDisabled
Then my security config looks like this:
#Configuration
public class SecurityConfig {
// When the securityDisabled profile is applied the following configuration gets used
#Profile("securityDisabled")
#EnableWebSecurity
public class SecurityDisabledConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
// Configure http as needed from Spring Security defaults when
// NO security is desired
}
}
// When the securityDisabled profile is NOT applied the following configuration gets used
#Profile("!securityDisabled")
#EnableGlobalMethodSecurity(prePostEnabled = true)
#EnableWebSecurity
public class SecurityEnabledConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
// Configure http as needed from Spring Security defaults when
// security is desired
}
}
}
In Springboot2, a simple solution consists in replacing the security method interceptor by a dummy one when the security is off :
#EnableGlobalMethodSecurity(prePostEnabled = true)
static class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
#Value("${disableSecurity}")
private boolean disableSecurity;
public MethodInterceptor methodSecurityInterceptor(MethodSecurityMetadataSource methodSecurityMetadataSource) {
return disableSecurity ? new SimpleTraceInterceptor()
: super.methodSecurityInterceptor(methodSecurityMetadataSource);
}
}
Thanks to Rob Winch for the solution. For folks who would like to do something similar but with prePostEnabled i have tried and tested the below similar approach and works just fine.
#EnableGlobalMethodSecurity(securedEnabled = true)
#Configuration
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
#Value("${security.prePostEnabled}")
private boolean prePostEnabled;
#Autowired
private DefaultMethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler;
protected MethodSecurityMetadataSource customMethodSecurityMetadataSource() {
return prePostEnabled ? new PrePostAnnotationSecurityMetadataSource(new ExpressionBasedAnnotationAttributeFactory(defaultMethodSecurityExpressionHandler)) : null ;
}}
EDIT: In addition to above i realized it is required to add following beans to the class. The below will help using the expression based pre invocation checks along with avoiding "ROLE_" prefix that is defaulted in all the handlers
protected AccessDecisionManager accessDecisionManager() {
AffirmativeBased accessDecisionManager = (AffirmativeBased) super.accessDecisionManager();
ExpressionBasedPreInvocationAdvice expressionAdvice = new ExpressionBasedPreInvocationAdvice();
expressionAdvice.setExpressionHandler(getExpressionHandler());
//This is required in order to allow expression based Voter to allow access
accessDecisionManager.getDecisionVoters()
.add(new PreInvocationAuthorizationAdviceVoter(expressionAdvice));
//Remove the ROLE_ prefix from RoleVoter for #Secured and hasRole checks on methods
accessDecisionManager.getDecisionVoters().stream()
.filter(RoleVoter.class::isInstance)
.map(RoleVoter.class::cast)
.forEach(it -> it.setRolePrefix(""));
return accessDecisionManager;
}
/**
* Allow skip ROLE_ when check permission using #PreAuthorize, like:
* #PreAuthorize("hasAnyRole('USER', 'SYSTEM_ADMIN')")
* Added all the Beans
*/
#Bean
public DefaultMethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler() {
DefaultMethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler = new DefaultMethodSecurityExpressionHandler();
defaultMethodSecurityExpressionHandler.setDefaultRolePrefix("");
return defaultMethodSecurityExpressionHandler;
}

How do I stop spring FilterRegistrationBean from registering my filter on /*

I am using spring-boot and I have declared a filter like so:
public static class ZeroLeggedOAuthProviderProcessingFilter extends ProtectedResourceProcessingFilter {
ZeroLeggedOAuthProviderProcessingFilter(LTIConsumerDetailsService ltiConsumerDetailsService, LTIOAuthNonceServices ltioAuthNonceServices, OAuthProcessingFilterEntryPoint oAuthProcessingFilterEntryPoint, OAuthAuthenticationHandler oAuthAuthenticationHandler, OAuthProviderTokenServices oauthProviderTokenServices) {
super();
log.info("CONSTRUCT Zero Legged OAuth provider");
setAuthenticationEntryPoint(oAuthProcessingFilterEntryPoint);
setAuthHandler(oAuthAuthenticationHandler);
setConsumerDetailsService(ltiConsumerDetailsService);
setNonceServices(ltioAuthNonceServices);
setTokenServices(oauthProviderTokenServices);
//setIgnoreMissingCredentials(false); // die if OAuth params are not included
}
}
#Bean(name = "zeroLeggedOAuthProviderProcessingFilter")
public ZeroLeggedOAuthProviderProcessingFilter oauthProviderProcessingFilter() {
return new ZeroLeggedOAuthProviderProcessingFilter(oauthConsumerDetailsService, oauthNonceServices, oauthAuthenticationEntryPoint(), oauthAuthenticationHandler, oauthProviderTokenServices());
}
I apply that filter to a single path like so (which seems to work):
#Configuration
#Order(1) // HIGHEST
public static class OAuthSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Autowired
ZeroLeggedOAuthProviderProcessingFilter oauthProviderProcessingFilter;
#Override
protected void configure(HttpSecurity http) throws Exception {
// filters must be ordered: see http://docs.spring.io/spring-security/site/docs/3.2.0.RELEASE/apidocs/org/springframework/security/config/annotation/web/HttpSecurityBuilder.html#addFilter%28javax.servlet.Filter%29
http.antMatcher("/oauth/**")
.addFilterBefore(oauthProviderProcessingFilter, UsernamePasswordAuthenticationFilter.class)
.authorizeRequests().anyRequest().hasRole("OAUTH");
}
}
However, it ends up being applied to all paths and I think it is because of some automatic registration that is happening (based on this in the logs).
o.s.b.c.embedded.FilterRegistrationBean : Mapping filter:
'zeroLeggedOAuthProviderProcessingFilter' to: [/*]
Is there a way to stop my filter from being automatically registered?
I ended up solving it this way instead (since the FilterRegistrationBean caused other problems).
My filter definition:
public static class ZeroLeggedOAuthProviderProcessingFilter extends ProtectedResourceProcessingFilter {
ZeroLeggedOAuthProviderProcessingFilter(LTIConsumerDetailsService ltiConsumerDetailsService, LTIOAuthNonceServices ltioAuthNonceServices, OAuthProcessingFilterEntryPoint oAuthProcessingFilterEntryPoint, OAuthAuthenticationHandler oAuthAuthenticationHandler, OAuthProviderTokenServices oauthProviderTokenServices) {
super();
log.info("CONSTRUCT Zero Legged OAuth provider");
setAuthenticationEntryPoint(oAuthProcessingFilterEntryPoint);
setAuthHandler(oAuthAuthenticationHandler);
setConsumerDetailsService(ltiConsumerDetailsService);
setNonceServices(ltioAuthNonceServices);
setTokenServices(oauthProviderTokenServices);
//setIgnoreMissingCredentials(false); // die if OAuth params are not included
}
}
And my http config which applies that filter to the oauth path only:
#Configuration
#Order(1) // HIGHEST
public static class OAuthSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
private ZeroLeggedOAuthProviderProcessingFilter zeroLeggedOAuthProviderProcessingFilter;
#Autowired
LTIConsumerDetailsService oauthConsumerDetailsService;
#Autowired
LTIOAuthNonceServices oauthNonceServices;
#Autowired
OAuthAuthenticationHandler oauthAuthenticationHandler;
#Autowired
OAuthProcessingFilterEntryPoint oauthProcessingFilterEntryPoint;
#Autowired
OAuthProviderTokenServices oauthProviderTokenServices;
#PostConstruct
public void init() {
zeroLeggedOAuthProviderProcessingFilter = new ZeroLeggedOAuthProviderProcessingFilter(oauthConsumerDetailsService, oauthNonceServices, oauthProcessingFilterEntryPoint, oauthAuthenticationHandler, oauthProviderTokenServices);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// added filters must be ordered: see http://docs.spring.io/spring-security/site/docs/3.2.0.RELEASE/apidocs/org/springframework/security/config/annotation/web/HttpSecurityBuilder.html#addFilter%28javax.servlet.Filter%29
http.antMatcher("/oauth/**")
.addFilterBefore(zeroLeggedOAuthProviderProcessingFilter, UsernamePasswordAuthenticationFilter.class)
.authorizeRequests().anyRequest().hasRole("OAUTH");
}
}
This also solved another issue I was having where my filter was appearing before the security filters (which caused other issues) so I think this is the best solution. I wish there was some mechanism to tell spring to ignore a filter in the global filters listing as well but this works in the meantime since that does not exist.

Spring security - Access to a controller method based on an attribute

I'm configuring Spring Security across all my controllers.
I want some method executions to start only when "my system is enabled". This information is accessible from all over the controllers via a specific static method (I can make it non-static).
My point is that I want to avoid making an explicit check in java code at the beginning of every method.
How can I get there via Spring Security?
One approach is to use a handler interceptor.
Here is general idea:
(1) Configure url patterns which you want to block:
<util:list id="sysEnableCheckUrlPatterns" value-type="java.lang.String">
<beans:value>/module1/**</beans:value>
<beans:value>/module2/**</beans:value>
</util:list>
(2) Write an interceptor:
public class SysEnableCheckInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
/*
If system enabled then return true. Otherwise return false (and optionally write something in response)
*/
}
}
(3) Configure that interceptor. In 3.1 you can do it as follows:
#Configuration
public class AppConfig extends WebMvcConfigurerAdapter {
#Resource(name="sysEnableCheckUrlPatterns")
/* or use #Autowired or #Inject if you like */
private String[] sysEnableCheckUrlPatterns;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SysEnableCheckInterceptor()).addPathPatterns(sysEnableCheckUrlPatterns);
}
}
You can use SPEL (Spring Expression Language) in a security annotation.
See http://static.springsource.org/spring-security/site/docs/3.0.x/reference/el-access.html

Resources