Rest service with oauth2: Failed to find access token for token - spring-mvc

I try to create spring rest service, whis is autenticated by my own oauth2 resources server. I created resource server:
#Configuration
#EnableResourceServer
protected static class ResourceServer extends ResourceServerConfigurerAdapter {
#Autowired
private TokenStore tokenStore;
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.tokenStore(tokenStore).resourceId("mobileapp");
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/api/shop /**").authenticated().and()
.authorizeRequests().antMatchers("/auth/**").anonymous();
}
}
and authorization server:
#Configuration
#EnableAuthorizationServer
protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager auth;
#Autowired
private DataSource dataSource;
#Autowired
private BCryptPasswordEncoder passwordEncoder;
#Bean
public JdbcTokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
#Bean
protected AuthorizationCodeServices authorizationCodeServices() {
return new JdbcAuthorizationCodeServices(dataSource);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.passwordEncoder(passwordEncoder);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.authorizationCodeServices(authorizationCodeServices())
.authenticationManager(auth)
.tokenStore(tokenStore())
.approvalStoreDisabled();
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource)
.passwordEncoder(passwordEncoder);
.withClient("mobile")
.authorizedGrantTypes("password", "refresh_token")
.authorities("ROLE_CLIENT")
.scopes("read", "write", "trust")
.autoApprove(true)
.resourceIds("mobileapp")
.secret("123456");
}
When I try to receive an access token from server, using curl:
curl -X POST -vu mobile:123456 http://localhost:8080/oauth/token -H
"Accept: application/json" -d
"password=test123&username=admin#gmail.com&grant_type=password&scope=read&client_secret=123456&client_id=mobile"
I get this error as a response message:
{"error":"server_error","error_description":"java.io.NotSerializableException:
org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"}
In tomcat logs there is also
o.s.s.o.p.token.store.JdbcTokenStore - Failed to find access token for
token
EDIT:
Bean definition of password encoder:
#Bean
public BCryptPasswordEncoder passwordEncoder() {
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
return bCryptPasswordEncoder;
}
This bean is created in class, in which OAuth2Config and ResourceServer are declared.
I checked code and found out which table spring uses and the table is empty. My question is: should it be auto generated or there is a problem with my code?
Thanks in advance for help.

Override JdbcTokenStore class and replace this function with.
public OAuth2AccessToken readAccessToken(String tokenValue) {
OAuth2AccessToken accessToken = null;
try {
accessToken = new DefaultOAuth2AccessToken(tokenValue);
}
catch (EmptyResultDataAccessException e) {
if (LOG.isInfoEnabled()) {
LOG.info("Failed to find access token for token "+tokenValue);
}
}
catch (IllegalArgumentException e) {
LOG.warn("Failed to deserialize access token for " +tokenValue,e);
removeAccessToken(tokenValue);
}
return accessToken;
}
Your problem of failed to find access token is resolved.Use this class in OAuth2Config.

Your model must have BCryptPasswordEncoder which is not serialized. Make it transient in your user bmodel.
private transient BCryptPasswordEncoder passwordEncoder;

The solution, as far as Postgres is concerned, use BYTEA for ALL token and authentication columns.
The columns are defined as LONGVARBINARY in this schema reference: https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/test/resources/schema.sql
In other words, replace LONGVARBINARY with BYTEA if you are using Postgres.
Cheers

Related

Spring Security with JWT: JWT filter which validates the token is not invoked

I am using Spring Security with JWT for authenticating rest apis. On login, the JWT token is generated and shared to the mobile client. But, the token in the subsequent requests are not been validated. Is there anything wrong in the security configuration ?
Spring security version - 5.1.6.RELEASE
// Security Configuration
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
#Autowired
private JwtTokenAuthenticationFilter jwtTokenAuthenticationFilter;
#Autowired
private CustomUserDetailsService customUserDetailsService;
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserDetailsService).passwordEncoder(passwordEncoder());
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.
httpBasic().disable().
csrf().disable().
exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).
and().
addFilterBefore(jwtTokenAuthenticationFilter, UsernamePasswordAuthenticationFilter.class).
sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).
and().
authorizeRequests().antMatchers("/user/login").permitAll().
antMatchers("/user/test").authenticated().
anyRequest().authenticated();
}
}
// JWT Token Auth Filter - This is never invoked
#Component
public class JwtTokenAuthenticationFilter extends GenericFilterBean {
#Autowired
private JwtTokenProvider jwtTokenProvider;
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws IOException, ServletException {
String token = jwtTokenProvider.resolveToken((HttpServletRequest) req);
if (null != token && jwtTokenProvider.validateToken(token)) {
Authentication auth = jwtTokenProvider.getAuthentication(token);
if (null != auth) {
SecurityContextHolder.getContext().setAuthentication(auth);
}
}
filterChain.doFilter(req, res);
}
}
I was expecting that all the requests after login will be authenticated against the JWT token.
I tried putting the name of the service to be authenticated as below:
antMatchers("/user/test").authenticated().
Also, any request authenticated is also added, but neither of them worked.
anyRequest().authenticated();
Try to replace
addFilterBefore(jwtTokenAuthenticationFilter, UsernamePasswordAuthenticationFilter.class).
by
addFilterBefore(jwtTokenAuthenticationFilter), BasicAuthenticationFilter.class);
If not runs, change jwtTokenAuthenticationFilter class to avoid to be a Spring bean and use like this:
addFilterBefore(new JwtTokenAuthenticationFilter(jwtTokenProvider)), BasicAuthenticationFilter.class);
And add the following code on Security Class:
#Autowired
private JwtTokenProvider jwtTokenProvider;

exception handling for rabbitmq listener in spring

Working with spring, I am new to rabbitmq, i want to know where i am wrong.
I have written a rabbitmq connection factory, and a listener container containing a listener. I have also provided the listener container with an error handler but it doesnt seems to work.
My spring beans:
<rabbit:connection-factory id="RabbitMQConnectionFactory" virtual-host="${rabbitmq.vhost}" host="${rabbitmq.host}" port="${rabbitmq.port}" username="${rabbitmq.username}" password="${rabbitmq.password}"/>
<rabbit:listener-container missing-queues-fatal="false" declaration-retries="0" error-handler="errorHandlinginRabbitMQ" recovery-interval="10000" auto-startup="${rabbitmq.apc.autostartup}" max-concurrency="1" prefetch="1" concurrency="1" connection-factory="RabbitMQConnectionFactory" acknowledge="manual">
<rabbit:listener ref="apcRabbitMQListener" queue-names="${queue.tpg.rabbitmq.destination.apc}" exclusive="true" />
</rabbit:listener-container>
<bean id="errorHandlinginRabbitMQ" class="RabbitMQErrorHandler"/>
This is my RabbitMQErrorHandler class:
public class RabbitMQErrorHandler implements ErrorHandler
{
#Override
public void handleError(final Throwable exception)
{
System.out.println("error occurred in message listener and handled in error handler" + exception.toString());
}
}
What i assume is, if i provide invalid credentials to the connection factory, handleError method of the RabbitMQErrorHandler class should execute, and the server should start properly, however, when i try to run the server, the method does not executes(the exception is thrown in console) and the server is not able to start. Where am i missing something and what that might be?
The error handler is for handling errors during message delivery; since you haven't connected yet, there is no message for which to handle an error.
To get connection exceptions, you should implement ApplicationListener<ListenerContainerConsumerFailedEvent> and you will receive the failure as an event if you add it as a bean to the application context.
You will get other events (consumer started, consumer stopped etc) if you implement ApplicationListener<AmqpEvent>.
EDIT
<rabbit:listener-container auto-startup="false">
<rabbit:listener id="fooContainer" ref="foo" method="handleMessage"
queue-names="si.test.queue" />
</rabbit:listener-container>
<bean id="foo" class="com.example.Foo" />
Foo:
public class Foo {
public final CountDownLatch latch = new CountDownLatch(1);
public void handleMessage(String foo) {
System.out.println(foo);
this.latch.countDown();
}
}
App:
#SpringBootApplication
#ImportResource("context.xml")
public class So43208940Application implements CommandLineRunner {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(So43208940Application.class, args);
context.close();
}
#Autowired
private SimpleMessageListenerContainer fooContainer;
#Autowired
private CachingConnectionFactory connectionFactory;
#Autowired
private RabbitTemplate template;
#Autowired
private Foo foo;
#Override
public void run(String... args) throws Exception {
this.connectionFactory.setUsername("junk");
try {
this.fooContainer.start();
}
catch (Exception e) {
e.printStackTrace();
}
Thread.sleep(5000);
this.connectionFactory.setUsername("guest");
this.fooContainer.start();
System.out.println("Container started");
this.template.convertAndSend("si.test.queue", "foo");
foo.latch.await(10, TimeUnit.SECONDS);
}
}

How to create a Spring Interceptor for Spring RESTful web services

I have some Spring RESTful (RestControllers) web services with no web.xml and I am using Spring boot to start the services.
I want to add authorization layer for the web services and wanted to route all the http requests to one front controller before actually calling the web service itself. (I have a code to simulate sessions behavior at the autherisation layer, to validate a user based on a generated key that I send with each of the httpRequest from the client).
Is there any Standard Spring solution on routing all the requests to a filter /front controller?
Thanks in advance,
Praneeth
Edit:
Adding my code
Controller:
`
#RestController
public class UserService {
UserDAO userDAO = new UserDAO();
#RequestMapping(value="/login", method = RequestMethod.POST)
#LoginRequired
public String login(#RequestParam(value="user_name") String userName, #RequestParam(value="password") String password, HttpServletRequest request){
return userDAO.login(userName, password);
}
}`
Interceptor:
`
public class AuthenticationInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("In Interceptor");
//return super.preHandle(request, response, handler);
return true;
}
#Override
public void postHandle( HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("---method executed---");
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
System.out.println("---Request Completed---");
}
}
`
Interface.
`
#Target({ElementType.METHOD, ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
public #interface LoginRequired {
}
`
Following steps can be taken to implement the interceptor with Spring:
Implement an interceptor class extending HandlerInterceptorAdapter class. Following is how the code could look like:
public class LoginInterceptor extends HandlerInterceptorAdapter {
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception)
throws Exception {
// TODO Auto-generated method stub
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception {
// TODO Auto-generated method stub
}
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HandlerMethod handlerMethod = (HandlerMethod) handler;
String emailAddress = request.getParameter("emailaddress");
String password = request.getParameter("password");
if(StringUtils.isEmpty(emailAddress) || StringUtils.containsWhitespace(emailAddress) ||
StringUtils.isEmpty(password) || StringUtils.containsWhitespace(password)) {
throw new Exception("Invalid User Id or Password. Please try again.");
}
return true;
}
}
Implement an AppConfig class or add the addInterceptors in one of the existing Configuration class. Note the path pattern specified with the LoginInterceptor instance
#Configuration
public class AppConfig extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/account/login");
}
}
Implement the controller method such as following:
#Controller
#RequestMapping("/account/login")
public class LoginController {
#RequestMapping(method = RequestMethod.GET)
public String login() {
return "login";
}
}
here an example of Interceptor :
public class AuthenticationInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
HandlerMethod handlerMethod = (HandlerMethod) handler;
LoginRequired loginRequired = handlerMethod.getMethod().getAnnotation(LoginRequired.class);
if (loginRequired == null) {
return true;
}
String token = httpServletRequest.getParameter("token");
if (StringUtils.isBlank(token)) {
throw new MissingParameterException();
}
authenticationService.checkToken(token);
return super.preHandle(httpServletRequest, httpServletResponse, handler);
}
#Override
public void postHandle( HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("---method executed---");
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
System.out.println("---Request Completed---");
}
We can create an annotation :
#Target({ElementType.METHOD, ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
public #interface LoginRequired {
}
And then on controller, we had this annotation :
#RequestMapping(value = "/protected/controller")
#LoginRequired
public ResponseEntity<BaseResponse> controller() {
...
}
This is just a template/example to give you an idea.
I hope this will help you.
There is a default solution for such things.
spring security. And you will just have to implement something like:
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.formLogin()
.loginPage("/login")
.failureUrl("/login?error")
.usernameParameter("email")
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/")
.permitAll();
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(new BCryptPasswordEncoder());
}
}
the dependency for it is:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
After Spring 5 :
Implementation should be like this: We should have a class that implements
HandlerInterceptor
public class CustomInterceptor implements HandlerInterceptorr{
}
Then we can register this interceptor by a class that implements WebMvcConfigurer
and override the method addInterceptors
public class ServiceInterceptorAppConfig implements WebMvcConfigurer {
#Autowired
CustomInterceptor customInterceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(customInterceptor);
}
}
You should add this to regsiter your interceptor
#Configuration
public class MyConfiguration extends WebMvcConfigurerAdapter {
#Bean
AuthenticationInterceptor getAuthenticationInterceptor() {
return new AuthenticationInterceptor();
}
#Override
public void addInterceptors (InterceptorRegistry registry) {
registry.addInterceptor(getAuthenticationInterceptor());
}
}
If you looking for simple answer for spring boot application..
public class HttpInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// do something here.
return true;
}
}
and
#Configuration
public class AppConfig implements WebMvcConfigurer {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new HttpInterceptor());
// registry.addInterceptor(new HttpInterceptor()).addPathPatterns("/account/login"); you can add specific end point as well.
}
}

spring security webSecurity.ignoring()

I am using spring security via spring boot.
I have two kinds of rest services.
public/** --> Every one can access and use these services
secure/** --> Only authenticated users can use.
#Slf4j
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
public void configure(WebSecurity webSecurity) throws Exception {
webSecurity.ignoring().antMatchers("/public/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(requestHeaderAuthenticationFilter(authenticationManager()),
BasicAuthenticationFilter.class)
.authorizeRequests().antMatchers("/secure/**").fullyAuthenticated();
}
#Bean
public RequestHeaderAuthenticationFilter requestHeaderAuthenticationFilter(
final AuthenticationManager authenticationManager) {
RequestHeaderAuthenticationFilter filter = new RequestHeaderAuthenticationFilter();
filter.setAuthenticationManager(authenticationManager);
filter.setExceptionIfHeaderMissing(true);
filter.setPrincipalRequestHeader("MY_HEADER");
filter.setInvalidateSessionOnPrincipalChange(true);
filter.setCheckForPrincipalChanges(false);
filter.setContinueFilterChainOnUnsuccessfulAuthentication(false);
return filter;
}
When i want to access a resource under public i got exception.
exception: "org.springframework.security.web.authentication.preauth.PreAuthenticatedCredentialsNotFoundException"
message: "MY_HEADER header not found in request."
Why does my filter activated under public resource while it is configured as ignored resource?
Thanks is advance
This is an issue in WebSecurity.ignoring() as discussed in Spring Security Github when using Beans as Filters.
You can work around this by removing the #Bean annotation in your Filter declaration.
// #Bean - Remove or Comment this
public RequestHeaderAuthenticationFilter requestHeaderAuthenticationFilter(
final AuthenticationManager authenticationManager) {
RequestHeaderAuthenticationFilter filter = new RequestHeaderAuthenticationFilter();
filter.setAuthenticationManager(authenticationManager);
filter.setExceptionIfHeaderMissing(true);
filter.setPrincipalRequestHeader("MY_HEADER");
filter.setInvalidateSessionOnPrincipalChange(true);
filter.setCheckForPrincipalChanges(false);
filter.setContinueFilterChainOnUnsuccessfulAuthentication(false);
return filter;
}

Spring Security OAuth - how to enable private or public access token accessing different resources?

I have two end-points.
/foo - is a internal (semi-private) endpoint. It is allowed only for the clients configured. (No userName and credentials are needed; but clientID is sufficient)
/greetings - is a private endpoint. It is allowed only for clients and user configured. (both clientID and username and password is required)
Here is the configuration.
#Configuration
public class OAuth2ServerConfiguration {
private static final String RESOURCE_ID = "restservice";
#Configuration
#EnableResourceServer
protected static class ResourceServerConfiguration extends
ResourceServerConfigurerAdapter {
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
// #formatter:off
resources
.resourceId(RESOURCE_ID);
// #formatter:on
}
#Override
public void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
.authorizeRequests()
.antMatchers("/users").hasRole("ADMIN")
.antMatchers("/greeting").authenticated()
.antMatchers("/foo").authenticated();
// #formatter:on
}
}
#Configuration
#EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends
AuthorizationServerConfigurerAdapter {
private TokenStore tokenStore = new InMemoryTokenStore();
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Autowired
private CustomUserDetailsService userDetailsService;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
// #formatter:off
endpoints
.tokenStore(this.tokenStore)
.authenticationManager(this.authenticationManager)
.userDetailsService(userDetailsService);
// #formatter:on
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// #formatter:off
clients
.inMemory()
.withClient("clientapp")
.authorizedGrantTypes("password", "refresh_token","authorization_code")
.authorities("USER","ROLE_CLIENT")
.scopes("read", "write")
.resourceIds(RESOURCE_ID)
.secret("123456")
.accessTokenValiditySeconds(600);
// #formatter:on
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setSupportRefreshToken(true);
tokenServices.setTokenStore(this.tokenStore);
return tokenServices;
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception
{
oauthServer.checkTokenAccess("permitAll()");
}
}
}
Here is the controller
#RestController
public class GreetingController {
private static final String template = "Hello, %s! your password is %s";
private final AtomicLong counter = new AtomicLong();
#RequestMapping("/greeting")
public Greeting greeting(#AuthenticationPrincipal User user) {
return new Greeting(counter.incrementAndGet(), String.format(template, user.getName(),user.getPassword()));
}
#RequestMapping("/foo")
public String foo(#AuthenticationPrincipal User user) {
System.out.println(user==null);
return "you are permitted here";
}
}
I am NOT able to access http://localhost:9001/foo without any token.
so when I try to get access token using the curl below ( note I do not pass username and password, only client_id and client_secret is passed)
curl -X POST -vu clientapp:123456 http://localhost:9001/oauth/token -H "Accept: application/json" -d "grant_type=password&scope=read%20write&client_secret=123456&client_id=clientapp"
I get this error
{"error":"invalid_grant","error_description":"Bad credentials"}
something is wrong with my configuration. I am a beginner using Spring security OAuth. would appreciate any help here.
thanks
I think you are passing wrong grant_type...
curl -X POST -vu clientapp:123456 http://localhost:9001/oauth/token -H "Accept: application/json" -d "grant_type=client_credentials&scope=read%20write&client_secret=123456&client_id=clientapp"
Also as far as I remember you shouldn't duplicate client_id and client_secret in the header and body of request.. Only header should be enough

Resources