I'm trying to return some User data after a successful login in a Spring Boot application.
To do so, I need to serialize my Principal with the Jackson mapper that is already set-up at bootstrap via a factory.
Is there a way to inject it into the authentication handler?
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
response.setStatus(HttpServletResponse.SC_OK);
UserDetails me = (UserDetails) authentication.getPrincipal();
PrintWriter writer = response.getWriter();
/*mapper.writeValue(writer, user); <- how to get the mapper?
writer.flush();*/
}
tl;dr;
Instead of using a Factory, make the ObjectMapper a Spring bean. That way it can be injected into both Spring and Jersey components.
#Bean
public ObjectMapper mapper() {
ObjectMapper mapper = new ObjectMapper();
return mapper;
}
When you use an HK2 (Jersey's DI framework) Factory to create the ObjectMapper, the injection is only available to components that are retrieved through the HK2 ServiceLocator, which is the HK2 analogue of the Spring ApplicationContext.
When you use Spring-Boot with Jersey, how the two interact under the hood, is through the HK2 spring-bridge. So for example, say the AuthenticationSuccessHandler is registered in the ApplicationContext. With the spring-bridge configured, we can also get the AuthenticationSuccessHandler through the ServiceLocator
ServiceLocator l = ...
AuthenticationSuccessHandler handler = l.getService(AuthenticationSuccessHandler.class);
That should work. If you have the ObjectMapper binded through an HK2 Factory, and you were to #Inject the mapper into the AuthenticationSuccessHandler, it would be injected, when retrieved through the ServiceLocator.
That being said, Spring Security doesn't go through HK2, so it never has a chance to get the ObjectMapper through HK2. But if you register the mapper as a Spring bean, then Spring can inject it into the AuthenticationSuccessHandler. And the mapper is still available through HK2 ServiceLocator (because of the spring-bridge), so you can still use it with Jersey, same way as if it were binded with a Factory.
Related
Assuming we got an annotated rest controller method with:
#PreAuthorize("hasPermission(#username, 'USER_PROFILE', 'WRITE')")
In Spring MVC we would implement a PermissionEvaluator to implement the authorization hidden behind the following method signature
boolean hasPermission(
Authentication authentication,
Serializable targetId,
String targetType,
Object permission
)
This still seems to work when using Spring WebFlux as long as you do not need to call a reactive service/method inside of the hasPermission method, which I guess is rarely the case since you would typically like to use the reactive interface for your database layer as well. If you would call a reactive service inside this method anyway you would need to call block() on some Mono at some time and thereby run into trouble since you are called from within a reactive pipeline.
In the tutorial from Josh Long about Security with Spring WebFlux he explains how to implement authorization directly on the SecurityWebFilterchain using path matchers by providing custom ReactiveAuthorizationManagers. But there is no explanation of how to use the PreAuthorize annotation in Spring WebFlux.
I was expecting to implement some ReactivePermissionEvaluator
Mono<Boolean> hasPermission(
Authentication authentication,
Serializable targetId,
String targetType,
Object permission
)
that would allow using reactive services in the implementation as well but I wasn't able to find any implementation of the ReactiveAuthorizationManager that would scan for the PreAuthorize annotation and dispatch the evalutation to a reactive PermissionEvaluator nor does the ReactivePermissionEvaluator interface exist.
So finally the question is, how to implement a reactive PermissionEvaluator that allows calling a reactive service, e.g. to query the database for the autorization information without blocking?
Sadly... this is not yet supported by Spring Security in https://github.com/spring-projects/spring-security/issues/5046
Here is how you should do it. Just get DefaultMethodSecurityExpressionHandler bean from applicationContext and explicitly replace permissionsEvaluator.
#Configuration
#EnableWebFluxSecurity
#EnableReactiveMethodSecurity
public class SecurityConfiguration {
#Autowire
private ApplicationContext applicationContext;
#Bean
#DependsOn({"methodSecurityExpressionHandler"})
public SecurityWebFilterChain springSecurityFilterChain(
ServerHttpSecurity http) {
DefaultMethodSecurityExpressionHandler defaultWebSecurityExpressionHandler = this.applicationContext.getBean(DefaultMethodSecurityExpressionHandler.class);
defaultWebSecurityExpressionHandler.setPermissionEvaluator(permissionEvaluator());
return http.csrf().disable()
.httpBasic().disable()
.formLogin().disable()
.logout().disable()
.securityContextRepository(NoOpServerSecurityContextRepository.getInstance())
.addFilterAt(tokenAuthenticationFilter(), SecurityWebFiltersOrder.AUTHENTICATION)
.authorizeExchange()
.anyExchange().authenticated()
.and().build();
}
PermissionEvaluator permissionEvaluator() {
return new PermissionEvaluator() {
#Override
public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
//Custom logic to evaluate #PreAuthorize("hasPermission('123', '123')")
return false;
}
#Override
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
//Custom logic to evaluate #PreAuthorize("hasPermission('123', '123','123')")
return false;
}
};
}
I have a question that comes from reading a lot of examples from Spring user and oauth2 but still failing at some basic concepts, maybe someone can point me in good directions/examples or of information to read.
so I'm trying to build a rest based API application.
to access the endpoints they will be protected by a JWT token and the idea is that the token is used for SSO across several other applications.
my initial idea was to have some authentication filter interceptors that process the token so I can store whatever additional information I may need and then use that user in the actual business layer of my services.
I've implemented some AuthenticationFiler that implements Filter
and I can get the additional information after I read the token access from my token store.
Now my first problem starts in fact that most of the examples start by the login/logout page and since I'm having more of an API setup I really don't have that flow.
Second, it seems most times the way to get the user is from the principal (SecurityContextHolder.getContext().getAuthentication().getPrinciple()) something like this but my principal is always null, not sure if this is because I don't really know if this is because of the stateful vs. stateless or the sorts.
So my biggest problems are to understand how can I share user details between my security interceptor and my business layer. maybe this questions is not so much about spring per se and I have more basic knowledge missing but maybe someone can give me some pointers.
this is my authentication filter, what I want to know is how can I create a user instance the same way I can use the MDC to store the user information.
Ideally, I would like to create a user instance there and just pass it to the business layer. can I do that with an Autowire?
#Component
#Order(Ordered.LOWEST_PRECEDENCE)
public class AuthenticationFilter implements Filter {
#Autowired
TokenStore tokenStore;
#Autowired
JwtAccessTokenConverter accessTokenConverter;
#Override
public void init(FilterConfig filterConfig) {
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null) {
if (authentication instanceof OAuth2Authentication) {
OAuth2Authentication oAuth2Authentication = (OAuth2Authentication) authentication;
OAuth2AuthenticationDetails oauth2AuthenticationDetails = (OAuth2AuthenticationDetails)oAuth2Authentication.getDetails();
OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(oauth2AuthenticationDetails.getTokenValue());
Object decodedDetails = oauth2AuthenticationDetails.getDecodedDetails();
Map<String, Object> additionalInformation = oAuth2AccessToken.getAdditionalInformation();
MDC.put("sub", additionalInformation.get("sub").toString());
MDC.put("preferred_username", additionalInformation.get("preferred_username").toString());
}
}
try {
chain.doFilter(request, response);
}
finally {
MDC.remove("sub");
MDC.remove("preferred_username");
}
}
#Override
public void destroy() {
}
}
not sure if this is my miss-understanding but I think what I'm looking for is dependency injections.
somehow I wanto create a new User Bean, fill it in my filter and consumer it elsewhere.
I guess I could do a #autowire in my business layer and set it in the filter and use it in the business layer?
is this a bad pattern?
As far as I understand you architecture, you are developing this:
Rest API, which should be protected by JWT.
and you want this:
Access user information received in incoming JWT in your business layer.
If both of the above assumptions are correct, you should read about how spring is doing this in it's microservice architecture. read this for quick start:
https://dzone.com/articles/json-web-tokens-with-spring-cloud-microservices
Hope this helps.
I want to write some kind of unit test which depends on Spring Security.
For example, I have some service method which uses some repository and marked with #PreAuthorize annotation. Repository I can mock with Mockito, there is no problem. Also I can mock Security Context by #WithSecurityContext annotation. But when I run test, the #PreAuthorize annotation is just ignored. Of course I can run that test with #SpringBootTest annotation as an integration test and in this case the Security Context is up but this way is heavy and slow.
Is there a way to run unit test with only Spring Security Context raised?
UPDATE
Made an example of such kind of test. Thanks to #Sam Brannen for giving right direction.
#ActiveProfiles("method-security-test")
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {ExampleService.class, ExampleServiceTest.MethodSecurityConfiguration.class})
public class ExampleServiceTest {
private ExampleService service;
#Autowired
public void setService(ExampleService service) {
this.service = service;
}
#Test
#WithMockUser(username = "john_doe")
public void testAuthenticated() {
String actualMessage = service.example();
Assert.assertEquals("Message of john_doe", actualMessage);
}
#Test(expected = AuthenticationException.class)
public void testNotAuthenticated() {
service.example();
Assert.fail();
}
#TestConfiguration
#EnableGlobalMethodSecurity(prePostEnabled = true)
static class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
}
}
#Service
class ExampleService {
#PreAuthorize("isAuthenticated()")
String example() {
Principal principal = SecurityContextHolder.getContext().getAuthentication();
return "Message of " + principal.getName();
}
The #PreAuthorize annotation from Spring Security will only be honored if Spring Security proxies your component (e.g., service bean).
The simplest way to make that happen is by annotating an #Configuration class with #EnableGlobalMethodSecurity(prePostEnabled = true), having your component registered as a bean (e.g., via component scanning or an #Bean method), and including your AuthenticationManager setup.
You can then create a focused integration test using #ContextConfiguration (without Spring Boot testing support) to load an ApplicationContext from your #Configuration class. And you can use #Autowired to get access to your proxied component which will be advised with the #PreAuthorize security check support.
You might find this old blog post useful as well for background information: https://spring.io/blog/2013/07/04/spring-security-java-config-preview-method-security/
I'm currently setting up a rather big existing project for dependency-injection with guice and would need to access the request scoped HttpServletRequest instance injected into the rest-endpoint via #Context. The reason I need the HttpServletRequest instance it to create an object RequestContext needed for multiple of the backend services.
I've tried to add a guice Provider class:
public class JerseyRequestCtxProvider implements Provider<IRequestContext> {
private final HttpServletRequest request;
#Inject
public JerseyRequestCtxProvider(HttpServletRequest request) {
this.request = request;
}
#Override
public IRequestContext get() {
return new RequestContext(request);
}
}
and finally add it to the guice module as so:
bind(IRequestCtx.class).toProvider(JerseyRequestCtxProvider.class);
I've also tried to have the HttpServletRequest as a Provider itself and added the guice servlet filter, but no luck there.
Is it even possible to get access to the HttpServletRequest in guice, if the endpoints are managed by jersey?
I'm working on an app that has to do object level security checks, and the checks will be made by a service because it will need to make REST calls to a separate application. Because of this I'm not able to use Spring Security roles or ACLs because none of this information will be stored locally in the app. I'm trying to find an elegant way to handle this, and here are two options I can think of:
1) Create a custom annotation that will check permissions
2) Extend a Spring security annotation permission check (possibly with Permission Evaluator?) that lets me write the logic for checking access
For #1 I've created a custom annotation and am using filters to read the annotation and check access, although this seems to be more brittle and will only give me protection for controller actions, and it would be nice to also secure other services as well.
I've found bits an pieces of this information, but nothing complete.
THIS talks about customizing ACL but only for a new permission, not controlling the logic
THIS talks about using SpEL, but I'd like to have checks before a method runs, to make sure that no effect takes place that would be unauthorized.
THIS appears to be the closest to what I want to do, but is specific to Spring Security and not Grails - my biggest challenge is converting the information in applicationContext.xml into resources.groovy
Thanks in advance for any suggestions or advice you may have!
You should be able to do this with spring security and grails without much trouble.
I used the following 2 ways in the past for similar tasks. Both require the spring security ACL plugin which provides the #PreAuthorize and #PostAuthorize annotations.
Custom PermissionEvaluator
You can use the hasPermission() methods within security annotations and create a custom PermissionEvaluator. Within code this looks like this:
#PreAuthorize("hasPermission(#myObject, 'update')")
public void updateSomething(myObject) {
..
}
The hasPermission() calls are routed to a PermissionEvaluator by spring security. To write your own implementation you have to implement the PermissionEvaluator interface:
class MyPermissionEvaluator implements PermissionEvaluator {
#Override
public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
// your custom logic..
}
#Override
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
// your custom logic
}
}
To register your PermissionEvaluator you have to override the bean named expressionHandler. You do this by adding the following lines in conf/spring/resources.groovy:
beans = {
expressionHandler(MyExpressionHandler) {
parameterNameDiscoverer = ref('parameterNameDiscoverer')
permissionEvaluator = ref('myPermissionEvaluator') // your PermissionEvaluator
roleHierarchy = ref('roleHierarchy')
trustResolver = ref('authenticationTrustResolver')
}
myPermissionEvaluator(MyPermissionEvaluator)
}
Within resources.groovy you can define beans like you would do in applicationContext.xml when using spring. The above lines create a bean of type MyPermissionEvaluator with the bean name myPermissionEvaluator. Spring securities expressionHandler bean is overridden with a bean of type MyExpressionHandler. The other dependencies are copied from the configuration file of the spring security ACL plugin.
Service calls in security annotations
If the design of the hasPermission() methods does not achive all you requirements you can use simple service calls instead. The #PostAuthorize and #PreAuthorize annotations use SPEL to evaluate the expression. Within SPEL you can use the # symbol to access beans. For example:
#PreAuthorize("#securityService.canAccess(#myObject)")
public void doSomething(myObject) {
..
}
This calls the canAccess method of the bean named securityService and passes the method argument to it.
To use this approach you have to register a BeanResolver on the EvaluationContext. To do this you have to override the DefaultMethodSecurityExpressionHandler which is configured by the spring security ACL plugin.
This can look like the following:
class MyExpressionHandler extends DefaultMethodSecurityExpressionHandler {
BeanResolver beanResolver
#Override
public EvaluationContext createEvaluationContext(Authentication auth, MethodInvocation mi) {
StandardEvaluationContext ctx = (StandardEvaluationContext) super.createEvaluationContext(auth, mi)
ctx.setBeanResolver(beanResolver) // set BeanResolver here
return ctx;
}
}
BeanResolver is a simple interface that resolves a bean name to a bean instance:
class GrailsBeanResolver implements BeanResolver {
GrailsApplication grailsApplication
#Override
public Object resolve(EvaluationContext evaluationContext, String beanName) throws AccessException {
return grailsApplication.mainContext.getBean(beanName)
}
}
And finally add the beans to resources.groovy:
expressionHandler(MyExpressionHandler) {
parameterNameDiscoverer = ref('parameterNameDiscoverer')
permissionEvaluator = ref('permissionEvaluator')
roleHierarchy = ref('roleHierarchy')
trustResolver = ref('authenticationTrustResolver')
beanResolver = ref('beanResolver') // this is your BeanResolver
}
// This is the service called within security expressions
// If you place your service in the grails service folder you can skip this line
securityService(MySecurityService)
// this is your BeanResolver
beanResolver(GrailsBeanResolver) {
grailsApplication = ref('grailsApplication')
}
Update (2013-10-22): Recently I wrote a blog post about exactly this which provides some additional information.