Using spring security annotations with keycloak - spring

I'm just a beginner in Spring Security, but I would like to know is it possible to configure keycloak in a way that I can use #PreAuthorize, #PostAuthorize, #Secured and other annotations.
For example, I've configured the keycloak-spring-security-adapter and Spring Security in my simple Spring Rest webapp so that I have access to Principal object in my controller, like this:
#RestController
public class TMSRestController {
#RequestMapping("/greeting")
public Greeting greeting(Principal principal, #RequestParam(value="name") String name) {
return new Greeting(String.format(template, name));
}
...
}
But when I try this (just an example, actually I want to execute custom EL expression before authorization):
#RestController
public class TMSRestController {
#RequestMapping("/greeting")
#PreAuthorize("hasRole('ADMIN')")
public Greeting greeting(Principal principal, #RequestParam(value="name") String name) {
return new Greeting(String.format(template, name));
}
...
}
I get exception:
org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext
In my spring security config I enabled global method security:
What do I need to make this spring security annotations work? Is it possible to use this annotation in this context at all?

here is example code:
#EnableWebSecurity
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true,
securedEnabled = true,
jsr250Enabled = true)
#ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
public class WebSecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
}
and
#PreAuthorize("hasRole('ROLE_ADMIN')")
Apart from this code. you need to do the role mapping for realm roles and client(application roles). the application roles will be put in #PreAuthorize

You still have to configure Spring Security using Keycloak. Take a look at the adapter documentation for an annotation based configuration. Once that's set up your Spring Security annotations will work on authorized calls.

Related

Reason for #EnableWebSecurity in the configuration class

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.

How does spring security pass credentials? / Postman

I just created a basic layer to secure my Spring API.
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
#Override
public UserDetailsService userDetailsService() {
List<UserDetails> users = new ArrayList<>();
users.add(User.withDefaultPasswordEncoder().username("Admin").password("xxx!!").roles("ADMIN").build());
users.add(User.withDefaultPasswordEncoder().username("Pharmacist").password("xxx!!").roles("PHARMACIST").build());
users.add(User.withDefaultPasswordEncoder().username("Office").password("xxx!!").roles("OFFICE").build());
return new InMemoryUserDetailsManager(users);
}
}
I am using Postman to test my endpoints and it's working via the Authorization function of Postman.
What if I want to use this parameters (username,password,role) in my frontend?
I mean, that I am trying somehow to see how spring security passes the values to the url: http://localhost:8080 but i cant find out how. I need this to be able to handle in my Frontend with these vaules.
I am really new in this Spring Security Chapter.

Spring Boot Security OAuth2 + Custom Permission Evaluator

I have a Spring boot (1.5.3) oauth2 application that has secured URL's and methods. Method security is currently working via:
#PreAuthorize("hasRole('ROLE_NAME')")
I'm now trying to add a custom PermissionEvaluator so that I can secure methods with
#PreAuthorize("hasPermission(#id, 'typeName', 'permissionName')").
I'm enabling this functionality by extending GlobalMethodSecurityConfiguration:
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true, mode =
AdviceMode.ASPECTJ, jsr250Enabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration
{
#Autowired
private MatterRepository matterRepository;
#Autowired
private MatterTeamMemberRepository matterTeamMemberRepository;
#Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
Map<String, Permission> permissionsMap = new HashMap<>();
permissionsMap.put(ReadMatterPermission.class.getSimpleName(),
new ReadMatterPermission(matterRepository, matterTeamMemberRepository));
OAuth2MethodSecurityExpressionHandler handler = new
OAuth2MethodSecurityExpressionHandler();
handler.setPermissionEvaluator(new
EntityPermissionEvaluator(permissionsMap));
return handler;
}
}
Note: PermissionEvaluator class omitted for brevity.
The problem I'm having is that hasPermission is sometimes invoked - most often it is not invoked. I suspect this is something to do with:
*Auto-configure an expression handler for method-level security (if the user
* already has
* {#code #EnableGlobalMethodSecurity}).
o.s.b.autoconfigure.security.oauth2.method.OAuth2MethodSecurityConfiguration
creating an instance of OAuth2MethodSecurityExpressionHandler before my configuration is processed.
Has anyone successfully injected a PermissionEvaluator into a spring boot oauth2 applicaion?
Thanks.
Turned out not to be a spring security configuration issue. The issue was related to aspectj compiler configuration in the pom. Long story short, fully qualified class name of AnnotationSecurityAspect was incorrect:
org.springframework.security.access.intercept.aspectj.AnnotationSecurityAspect
instead of
org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect
causing #PreAuthorize annotations to be ignored. My understanding that #PreAuthorize("hasRole...") was working was wrong - confused by the fact that tests sometimes succeeded when run through Eclipse but never when run via mvn on the command line.

How to designate public endpoints using custom annotation in spring rest controllers?

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

How to perform RunAs using method security with Spring MVC 3.2 and Spring Security 3.1

I have a web application with Spring MVC 3.2 and Spring Security 3.1
I'm using roles base security and have implemented UserDetailsService and UserDetails to provide GrantedAuthority.
I've enabled global method security with jsr250-annotations
Everything upto here is working as expected with signed in user method access restricted to the declared roles.
I have a further requirement to run certain methods called during application initialisation as a special user with a 'system role' ideally along the lines of JavaEE RunAs.
I'm not sure how to do this in Spring Security.
Should I be trying to create a PreAuthenticatedAuthenticationToken with some made up values and a 'system role' authority.
I could then do something likeSecurityContextHolder.getContext().setAuthentication(token);
when initialising the application.
Alternatively should I be trying to use the RunAsManager. It sounds like what I need but I have not found any simple examples of how I actually could use it.
I'm fairly new to Spring Security and I'm unsure of the best way to proceed.
When my application starts
I run a post construct method in my spring bean to create a special user in memory with a system role.
This user object implements the org.springframework.security.core.userdetails.UserDetails interface.
I then use the user to create a security token org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken
The token is then set in the Security Context.
#Service
#Transactional(readOnly = true)
public class ApplicationConfiguration{
#Inject
MyService myService;
#PostConstruct
#Transactional(readOnly = false)
public void init(){
// ######## Application Starting #######"
// Create a user that meets the contract of the Spring UserDetails interface
UserAccountImpl sysAcc = new UserAccountImpl("system", "system", "system");
UserRole role = new UserRole(Role.SYSTEM_ROLE);
role.addUserPermission(Permission.SYSTEM);
sysAcc.addUserRole(role);
UserDetailsAdapter userDetails = new UserDetailsAdapter(sysAcc);
// Create a token and set the security context
PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken( userDetails, userDetails.getPassword(), userDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(token);
// Now call service method with roles allowed
myService.initialiseSystem();
}
}
....
public interface MyService {
#RolesAllowed(SYSTEM)
public void initialiseSystem();
}
Do you really need to attach a role to the said app initialization? Why not just extract the code that needs to be run during initialization like so:
public interface Service {
#Secured("hasRole('USER')")
void service();
}
public class DefaultService implements Service {
#Override
public void service() {
doService();
}
public void doService() {
// Implementation here
}
}
...
public class AppInitializer {
#Autowired
private DefaultService service;
public void init() {
service.doService();
}
}
I believe that in this case a good solution for you would be to use the Spring Security OAuth because allow you have a greater integration to custom rules for access via tokens.
http://projects.spring.io/spring-security-oauth/

Resources