How do I mock an OAuth2Authentication Object in Spring Test - spring-security

I would like to test my rest controller in spring. In my the service, a user requires to pass an authentication token. I use a token utils class that decodes the token and get an organization id. I then use the id for several processes. How do I do a mock of this in Spring? I have followed this documentation but am getting a 404 on running the test.
TodoController
#RequestMapping("todos")
class TodoController {
#Autowired
lateinit var todoService: TodoService
#Autowired
lateinit var tokenUtils: TokenUtils
#GetMapping
fun getAllTodos(authentication: OAuth2Authentication): ResponseEntity<List<Todo>> {
tokenUtils.init(authentication);
val organizationId = tokenUtils.organizationId
return ResponseEntity.ok(todoService.findAll(organizationId))
}```
I am a bit new to spring tests and will appreciate any help accorded

First you need to create a mock Authentication class that implements Authentication interface. Most of following code is auto generated. Override any method you you need (in this case, I only override getPrincipal method).
import java.util.Collection;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
public class MockPrincipal implements Authentication {
public MockPrincipal() {}
#Override
public String getName() {
// TODO Auto-generated method stub
return null;
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
// TODO Auto-generated method stub
return null;
}
#Override
public Object getCredentials() {
// TODO Auto-generated method stub
return null;
}
#Override
public Object getDetails() {
// TODO Auto-generated method stub
return null;
}
#Override
public Object getPrincipal() {
// TODO Auto-generated method stub
return "mock user";
}
#Override
public boolean isAuthenticated() {
// TODO Auto-generated method stub
return false;
}
#Override
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
// TODO Auto-generated method stub
}
}
After that you can mock up an OAuth2Authentication object like this:
MockPrincipal mockUser = new MockPrincipal();
OAuth2Authentication mockOAuth2Object = new OAuth2Authentication(null, mockUser);

Related

How to access ReactiveSecurityContextHolder from ExceptionResolver?

I understand that in order to keep the context, the reactive chain of methods must not be broken. However, I need to get access to the context from the ExceptionResolver (after an exception has been thrown.)
My exception resolver is extending AbstractErrorWebExceptionHandler and when I try to get the context via ReactiveSecurityContextHolder.getContext() it returns empty. Obviously because the reactive chain has been broken.
How can I get access to the authentication object?
You can get access to the authentication object by overriding the handle method:
public class TestHandler extends AbstractErrorWebExceptionHandler {
public TestHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties,
ApplicationContext applicationContext) {
super(errorAttributes, resourceProperties, applicationContext);
}
#Override
protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
return null;
}
#Override
public Mono<Void> handle(ServerWebExchange exchange, Throwable throwable) {
Mono<Principal> authObject = exchange.getPrincipal();
//Handle exception here
return exchange.getResponse().setComplete();
}
}
Another approach is to implement the ErrorWebExceptionHandler directly:
public class TestHandler implements ErrorWebExceptionHandler {
#Override
public Mono<Void> handle(ServerWebExchange serverWebExchange, Throwable throwable) {
Mono<Principal> authObject = serverWebExchange.getPrincipal();
//Handle exception here
return serverWebExchange.getResponse().setComplete();
}
}

How to inject a bean into custom argument resolver?

Hello i use spring boot 1.3.2 version. I have a custom argument resolver which's name is ActiveCustomerArgumentResolver. Everything is great, resolveArgument method works fine but i can't initialize my service component which is of my custom arg. resolver. Is there a problem with lifecycle process? Here is my code:
import org.springframework.beans.factory.annotation.Autowired;
//other import statements
public class ActiveCustomerArgumentResolver implements HandlerMethodArgumentResolver {
#Autowired
private CustomerService customerService;
#Override
public boolean supportsParameter(MethodParameter parameter) {
if (parameter.hasParameterAnnotation(ActiveCustomer.class) && parameter.getParameterType().equals(Customer.class))
return true;
else
return false;
}
#Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
Principal userPrincipal = webRequest.getUserPrincipal();
if (userPrincipal != null) {
Long customerId = Long.parseLong(userPrincipal.getName());
return customerService.getCustomerById(customerId).orNull(); //customerService is still NULL here, it keeps me getting NullPointerEx.
} else {
throw new IllegalArgumentException("No user principal is associated with the current request, yet parameter is annotated with #ActiveUser");
}
}
}
Let the Spring create the resolver for you by making it a Component:
#Component
public class ActiveCustomerArgumentResolver implements HandlerMethodArgumentResolver {...}
Then inject the resolver into your WebConfig instead of simply using the new, like following:
#EnableWebMvc
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Autowired private ActiveCustomerArgumentResolver activeCustomerArgumentResolver;
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(activeCustomerArgumentResolver);
}
}
This is how i've solved the problem, not a generic one but helps me a lot:
#Configuration
#EnableAutoConfiguration
#ComponentScan
public class Application extends WebMvcConfigurerAdapter {
private static final Logger logger = LoggerFactory.getLogger(Application.class);
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(activeCustomerArgumentResolver());
}
#Bean
public ActiveCustomerArgumentResolver activeCustomerArgumentResolver() {
return new ActiveCustomerArgumentResolver();
}
}

Grails Spring Security get user by id

I'm writing Grails application with Spring Security plugin.
I have enabled queries generated by GORM into console and I have noticed that every request Security query the database about users, selecting them by it's username.
My intention is load user's by it's ID's, not usernames for increase performance.
I am aware that there is a possibility to overwrite UserDetailsService method loadUserByUsername(String username), but this method is used both for refreshing user's credential during the session and in login form, where in fact I want to authenticate user by it's username.
I have three questions:
How to load user by id? Should I inject user ID instead of username in GrailsUser (implementation of UserDetails) instead of regular username and use long selectById = Long.valueOf(String username)?
How to create different user provider for refreshing session to grab user by ID and different for user login (when I want to grab user by it's username/email)?
There is possibility to fetch user credentials not every request, but every X seconds?
Finally i managed to solve this problem. The queries are generated by:
springSecurityService.getCurrentUser()
Unfortunatelly, this method fetches User model class by username (from Principal object) and maps it into database field, at most configured by:
grails.plugin.springsecurity.userLookup.usernamePropertyName
as mentioned in documentation.
I have tried
grails.plugin.springsecurity.userLookup.usernamePropertyName = 'id'
but i received class-cast exception from String to Long.
Workaround is simple - create own Principle with username field typed as Long.
See PrincipalProxy in my solution:
package com.selly.util.security
import java.security.Principal;
import grails.plugin.springsecurity.userdetails.GrailsUser
import org.springframework.security.core.Authentication
import org.springframework.security.core.GrantedAuthority
class AppMetadataAuthenticationToken implements Authentication, Principal {
private boolean authenticated
private GrailsUser userDetails
private Principal principal
public AppMetadataAuthenticationToken(GrailsUser userDetails) {
this.userDetails = userDetails
this.principal = new PrincipalProxy(userDetails)
}
public GrailsUser getUser() {
return userDetails
}
public String getUsername() {
return userDetails.getUsername()
}
#Override
public String getName() {
return userDetails.getUsername()
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return userDetails.getAuthorities()
}
#Override
public Object getCredentials() {
return userDetails.password
}
#Override
public Object getDetails() {
return getUser()
}
#Override
public Object getPrincipal() {
return principal
}
#Override
public boolean isAuthenticated() {
return authenticated
}
#Override
public void setAuthenticated(boolean authenticated) throws IllegalArgumentException {
this.authenticated = authenticated
}
static class PrincipalProxy implements Principal {
GrailsUser grailsUser
Long username
public PrincipalProxy(GrailsUser grailsUser) {
this.grailsUser = grailsUser
this.username = grailsUser.id
}
#Override
public String getName() {
return grailsUser.id
}
}
}
To return this Token, just register your own AuthenticationProvider:
package com.selly.util.security;
import grails.plugin.springsecurity.SpringSecurityService
import org.springframework.security.authentication.AuthenticationProvider
import org.springframework.security.authentication.BadCredentialsException
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.authentication.dao.DaoAuthenticationProvider
import org.springframework.security.core.Authentication
import org.springframework.security.core.AuthenticationException
import org.springframework.security.core.userdetails.UserDetailsService
import org.springframework.security.core.userdetails.UsernameNotFoundException
public class AppUsernamePasswordAuthenticationProvider extends DaoAuthenticationProvider implements AuthenticationProvider {
SpringSecurityService springSecurityService
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
def token = (UsernamePasswordAuthenticationToken) authentication
def user = userDetailsService.loadUserByUsername(authentication.principal)
if(!user)
throw new UsernameNotFoundException("Cannot find user", authentication.principal)
if(!passwordEncoder.isPasswordValid(user.password, authentication.credentials, null))
throw new BadCredentialsException("Invalid password")
return new AppMetadataAuthenticationToken(user)
}
#Override
public boolean supports(Class<?> authentication) {
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
}
}
package com.selly.util.security;
import org.springframework.security.authentication.AuthenticationProvider
import org.springframework.security.core.Authentication
import org.springframework.security.core.AuthenticationException
public class AppMetadataAuthenticationProvider implements AuthenticationProvider {
#Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
// TODO Auto-generated method stub
return authentication;
}
#Override
public boolean supports(Class<?> authentication) {
// TODO Auto-generated method stub
return AppMetadataAuthenticationToken.class.isAssignableFrom(authentication);
}
}
Register it in resources.groovy
appUsernamePasswordAuthenticationProvider(AppUsernamePasswordAuthenticationProvider) {
userDetailsService = ref('userDetailsService')
passwordEncoder = ref('passwordEncoder')
userCache = ref('userCache')
saltSource = ref('saltSource')
preAuthenticationChecks = ref('preAuthenticationChecks')
postAuthenticationChecks = ref('postAuthenticationChecks')
springSecurityService = ref('springSecurityService')
}
And in Config.groovy:
grails.plugin.springsecurity.providerNames = [
'appMetadataAuthenticationProvider',
'appUsernamePasswordAuthenticationProvider',
// 'daoAuthenticationProvider',
// 'anonymousAuthenticationProvider',
// 'rememberMeAuthenticationProvider'
]
Now all works perfectly:
Hibernate: select this_.id as id13_0_, this_.account_expired as account2_13_0_, this_.account_locked as account3_13_0_, this_.enabled as enabled13_0_, this_."password" as password5_13_0_, this_.password_expired as password6_13_0_, this_.username as username13_0_, this_.workspace as workspace13_0_ from users this_ where (**this_.id=?**) limit ?
Instead of using getCurrentUser() you can also getPrincipal() and cast to your previously populated object with more data than Principal interface offers.

Spring security dynamically add users and authorities

How to generate "intercept-url" dynamically. My user name and roles are stored in database,
I want to map all these users in to spring security.Is there any way to do this?
You'll have to provide your own implementation of com.icod.solapCore.spring.security.FilterInvocationSecurityMetadataSource.
This could look like this :
public class MyFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
#Override
public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
FilterInvocation filterInvocation = (FilterInvocation) object;
HttpServletRequest request = filterInvocation.getHttpRequest();
Collection<ConfigAttribute> result = new ArrayList<ConfigAttribute>();
// Find roles in database that secures the specified request
// ...
// For any role found, create a SecurityConfig object prefixed with "ROLE_" ex :
// for(String role : roles) {
// ConfigAttribute attribute = new SecurityConfig("ROLE_"+roleFound);
// result.add(attribute);
// }
return result;
}
#Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}
#Override
public boolean supports(Class<?> clazz) {
return FilterInvocation.class.isAssignableFrom(clazz);
}
}
And then you'll have to replace the default FilterInvocationSecurityMetadataSource with your own. I do it with a BeanPostProcessor, called after spring read the configuration file but before it makes the configuration official. Looks like this :
public class MyFilterInvocationSecurityMetadataSourceBeanPostProcessor implements BeanPostProcessor {
private FilterInvocationSecurityMetadataSource metadataSource = new MyFilterInvocationSecurityMetadataSource();
#Override
public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException {
if (bean instanceof FilterInvocationSecurityMetadataSource) {
return metadataSource;
}
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String name) throws BeansException {
return bean;
}
}
Then you just have to configure the bean post processor :
<bean id="solapcoreFilterInvocationSecurityMetadataSourceBeanPostProcessor" class="foo.bar.MyFilterInvocationSecurityMetadataSourceBeanPostProcessor"/>
Hope this help.
Give all your users same role and operate with this role in config.
You can read abour roles here

Jersey #Context scope

I have a hard time understanding the injection mechanism of Jersey. The JAX-RS Specification (http://jsr311.java.net/nonav/releases/1.1/spec/spec3.html#x3-520005) states that injection via #Context is possible in Application subclasses, root resource classes and providers.
I now have a class that is instantiated at startup and has a method which is called on every request. Inside the method I need access to the current UriInfo object. The problem is, that this method is not called from my code. So I can't pass UriInfo directly to the method.
I actually want to do something like this:
public class MyClass implements ThirdPartyInterface {
// not possible because class is no Application subclass, root resource class or provider
#Context
private UriInfo uriInfo;
public void methodCallebByThirdPartyCode() {
Uri requestUri = uriInfo.getRequestUri();
// do something
}
}
I tried this. Obviously with no success:
public class MyClass implements ThirdPartyInterface {
private UriInfo uriInfo;
public MyClass(UriInfo uriInfo) {
this.uriInfo = uriInfo;
}
public void methodCallebByThirdPartyCode() {
Uri requestUri = uriInfo.getRequestUri();
// do something
}
}
#Provider
#Produces(MediaType.WILDCARD)
public class MyBodyWriter implements MessageBodyWriter<MyView> {
#Context
private UriInfo uriInfo;
private MyClass myClass;
private ThirdPartyClass thirdPartyClass;
public MyBodyWriter() {
// uriInfo is null at this time :(
myClass = new MyClass(uriInfo);
thirdPartyClass = new ThirdPartyClass();
thirdPartyClass.register(myClass);
}
public void writeTo(final MyView view, final Class<?> type, /* and so on */) throws IOException, WebApplicationException {
// execute() calls MyClass#methodCallebByThirdPartyCode()
thirdPartyClass.execute();
}
}
The only workaround I can think of is this. I don't think it's very clean:
public class MyClass implements ThirdPartyInterface {
private UriInfo uriInfo;
public void setUriInfo(final UriInfo uriInfo) {
this.uriInfo = uriInfo;
}
public void methodCallebByThirdPartyCode() {
Uri requestUri = uriInfo.getRequestUri();
// do something
}
}
#Provider
#Produces(MediaType.WILDCARD)
public class MyBodyWriter implements MessageBodyWriter<MyView> {
#Context
private UriInfo uriInfo;
private MyClass myClass;
private ThirdPartyClass thirdPartyClass;
public MyBodyWriter() {
myClass = new MyClass();
thirdPartyClass = new ThirdPartyClass();
thirdPartyClass.register(myClass);
}
public void writeTo(final MyView view, final Class<?> type, /* and so on */) throws IOException, WebApplicationException {
myClass.setUriInfo(uriInfo);
// execute() calls MyClass#methodCallebByThirdPartyCode()
thirdPartyClass.execute();
myClass.setUriInfo(null);
}
}
I hope there is a better solution, but maybe I'm completely on the wrong track.
Thanks!
Late answer, but a good question ... so lets go:
You can use a org.glassfish.hk2.api.Factory and javax.inject.Provider for injections. I don't know since which version this is available, so maybe you have to upgrade your jersery version. For the following samples i used jersey 2.12.
First you have to implement and register/bind a Factory for your MyClass:
MyClassFactory:
import javax.inject.Inject;
import javax.ws.rs.core.UriInfo;
import org.glassfish.hk2.api.Factory;
// ...
public class MyClassFactory implements Factory<MyClass> {
private final UriInfo uriInfo;
// we will bind MyClassFactory per lookup later, so
// the constructor will be called everytime we need the factory
// meaning, uriInfo is also per lookup
#Inject
public MyClassFactory(final UriInfo uriInfo) {
this.uriInfo = uriInfo;
}
#Override
public MyClass provide() {
return new MyClass(uriInfo)
}
#Override
public void dispose(UriInfo uriInfo) {
// ignore
}
}
Registration via ResourceConfig:
import org.glassfish.hk2.api.PerLookup;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.server.ResourceConfig;
// ...
public class MyResourceConfig extends ResourceConfig {
public MyResourceConfig() {
register(new AbstractBinder() {
#Override
protected void configure() {
bindFactory(MyClassFactory.class).to(MyClass.class).in(PerLookup.class);
// ... bind additional factories here
}
});
// ...
}
}
Now you are able to inject MyClass per lookup to providers, resources etc.
But Attention: Afaig there are two approaches and only one will work as eventually aspected for providers ...
import javax.inject.Inject;
import javax.ws.rs.Produces;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;
// ...
#Provider
#Produces("application/foo-bar")
public class MyBodyWriter implements MessageBodyWriter<MyView> {
// first approache - don't do it!
// will only injected once, cause MyBodyWriter is only instantiated once
#Inject
private MyClass myClass;
// second approache - works fine!
private final javax.inject.Provider<MyClass> provider;
// MyBodyWriter instantiate once
// get an inject provider here
#Inject
public MyBodyWriter(javax.inject.Provider<MyClass> myClassProvider) {
this.provider = myClassProvider;
}
#Override
public boolean isWriteable(Class<?> t, Type g, Annotation[] a, MediaType m) {
return t == MyView.class;
}
#Override
public long getSize(MyView t, Class<?> c, Type g, Annotation[] a, MediaType m) {
// deprecated by JAX-RS 2.0 and ignored by Jersey runtime
return 0;
}
#Override
public void writeTo(MyView v, Class<?> c, Type t, Annotation[] a, MediaType m, MultivaluedMap<String, Object> s, OutputStream o) throws IOException, WebApplicationException {
// attention: its not per lookup !!!
MyClass myClassDirectInjected = myClass;
System.out.println(myClassDirectInjected); // same instance everytime
// but this is ;)
MyClass myClassFromProvider = provider.get();
System.out.println(myClassFromProvider); // it's a new instance everytime
// ...
}
}
Hope this was somehow helpfull.

Resources