TestRestTemplate and spring security - spring-mvc

I am learning spring rest. I am slowly building an application. I had full integration testing working well using TestRestTemplate.
However, I just started adding spring security to my application. Literally as soon as I add the spring security dependency, my testing fails.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
I get these errors like so:
Error while extracting response for type [class [Lcom.myproject.model.viewobjects.AView;] and content type [application/json]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize instance of `[Lcom.myproject.model.viewobjects.AView;` out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `[Lcom.myproject.model.viewobjects.AView;` out of START_OBJECT token
at [Source: (PushbackInputStream); line: 1, column: 1]
When I debug, the object it returns which it is trying deserialize is null. If I put a breakpoint on the rest controller it doesn't even get there.
It seems like just adding the dependency turns a lot of defaults on. How do I test with security on?
1)Can I disable the security for testing somehow?
2)Can I somehow allow no credentials or send acceptable fake credentials? (I did see examples of #WithMockUser but that doesn't work with TestRestTemplate)
Edit:
I tried adding a security implementation to my test class to enable anonymous access and permitall:
#EnableWebSecurity
class TestSecurityConfig extends WebSecurityConfigurerAdapter
{
#Override
protected void configure(HttpSecurity http) throws Exception
{
http.anonymous().and().authorizeRequests().antMatchers("/**").permitAll();
}
}
The result of this is that #GetMapping work. I can trace that the calls reach the controller. But #PostMapping still do not work. The calls never reach the controller.
The post calls look like so:
updatedAView = restTemplate.postForObject(create_aview_url, aView, AView.class);
Why would get work but not post???
Also, to make sure there wasn't something else, I again went and removed the spring-boot-starter-security dependency and all the code that relates. Suddenly everything works. So it is definitely the security config that does this.

If you include the spring-boot-starter-security dependency, spring security is enabled by default. TestRestTemplate requests will be processed through the security system.
If you want to test without authentication, you can configure a version of WebSecurityConfigurerAdapter with #EnableWebSecurity for testing only that is permissive. You may need to exclude other configurations so they don't override this.
Here is an example:
#EnableWebSecurity
class TestSecurityConfig extends WebSecurityConfigurerAdapter
{
#Override
protected void configure(HttpSecurity http) throws Exception
{
http.anonymous().and().csrf().disable().authorizeRequests().antMatchers("/**").permitAll();
}
}
This allows you to make requests without user credentials
http.anonymous()
If you don't include the:
csrf().disable()
#GetMapping will work but no PostMapping or requests that change data as that is when csrf comes into play and it is enabled by default.
This permits you to access all the URLs in your application. You can of course limit this if you like:
authorizeRequests().antMatchers("/**").permitAll()

Related

How to secure a MVC application with OAuth2 using Spring?

Sorry, my English.
I have an application I can login in the usual way.
#Configuration
#EnableWebSecurity
public class LoginSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
System.out.println("LoginSecurityConfig :: configure");
auth.jdbcAuthentication().dataSource( getDataSource() )
.passwordEncoder( new BCryptPasswordEncoder(16) )
.usersByUsernameQuery(
"select user_name as username,password,enabled from users where user_name=?")
.authoritiesByUsernameQuery(
"select user_name as username, role_name from users_roles ur join users u on ur.user_id = u.user_id and u.user_name = ?");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/login*").anonymous()
.antMatchers("/resources/**").permitAll()
.antMatchers("/fotos/**").permitAll()
.antMatchers("/users").access("hasRole('ROLE_ADMIN')")
.antMatchers("/user").access("hasRole('ROLE_ADMIN')")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/loginPage")
.defaultSuccessUrl("/home", true)
.failureUrl("/loginPage?error=true")
.loginProcessingUrl("/login")
.usernameParameter("username")
.passwordParameter("password")
.and()
.logout()
.logoutSuccessUrl("/loginPage")
.invalidateHttpSession(true);
}
}
Using this I can try to access any secured resource and the system sends me to the loginPage where I can post username and password to the internal login controller then I have the Principal and can access the secured resources ( home, users, user ). Working fine.
But... I need to remove the user control database stuff and use OAuth2 to allow the same kind of access. I don't want to have any users in my database anymore. I need a login screen and then a token request like http://myserver/oauth/token?grant_type=password&username=admin&password=admin passing client_id and client_secret in Basic. I know how to do the "get token" part and my server is working fine and give me the token and refresh token but only using Postman because I have no idea how to use it in my web application code. All tutorials I've found are using both Server and Client in the same application and actually don't show how to consume an OAuth2 remote server.
Already try to use this. It is an excellent tutorial and very near to what I need but too complex to me.
I have this code and understand it can use the server and issue a token using the client credentials, but don't know how to give to the user a login screen and take his credentials to complete the request (the GET part).
#Configuration
#EnableResourceServer
public class OAuth2ResourceServerConfigRemoteTokenService extends ResourceServerConfigurerAdapter {
#Override
public void configure(final HttpSecurity http) throws Exception {
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and()
.authorizeRequests().anyRequest().permitAll();
}
#Primary
#Bean
public RemoteTokenServices tokenServices() {
final RemoteTokenServices tokenService = new RemoteTokenServices();
tokenService.setCheckTokenEndpointUrl("http://myoauthserver/oauth/check_token");
tokenService.setClientId("clientid");
tokenService.setClientSecret("password");
return tokenService;
}
}
so... how can I secure my system, take login and password from the user and use this code to control credentials like I was using usual database method?
Or OAuth2 is only for secure REST API?
Please be newbie friendly because I'm not very comfortable using Spring.
I’ve been working on this myself recently, and I wish I could say I have a simple answer, but I don’t. I would have to start by asking questions like, is this a web application (JSP etc) or a REST API used by a web application, or a REST API used by a mobile app, etc etc.
The reason this is important is that you first have to select one of the OAuth2 profiles and grant types, and they all have different requirements and configuration in Spring.
Also, are you trying to integrate with a third party OAuth2 authentication provider (e.g. Facebook) or is your application acting as both the authentication provider (where login and password validation occurs) and the protected resource (where the web page requests or API calls go to)?
So I guess the best I can do is assign you some homework:
(1) Read about the various OAuth2 profiles and determine which one best fits your application, and learn all the terminology (like, what is a client secret?).
This is definitely NOT one of those cases where you can just cut and paste example code without understanding it. If you don’t have a reasonable understanding of how OAuth2 works you are going to have a lot of difficulty.
Also: we’re talking about SECURITY here so doing stuff without understand it is a very bad idea. If you aren’t careful, you may think it’s working but in fact you’re leaving yourself wide open to attacks.
(2) if you are not familiar with Spring Framework Security you’ll need a basic grounding in that to understand what you’re doing.
(3) Once you have an idea which profile you’ll use, use that in a google search, e.g. “Spring oauth2 implicit grant” to find an example tailored for that profile.
There are a few out there and that’s a good place to start though I found I was not able to take any of the examples directly over to my application because of subtle differences in their assumptions and my application.
The Spring reference guide is helpful also but doesn’t necessarily give all the details for all the issues you may encounter. Finally, try to implement with your application.
You’ll want some good tools to send requests to your app (I like PostMan for that purpose) so you can inspect the data going back and forth. OAuth2 involves a complex series of HTTP redirects so testing can be a bit difficult.
Also, be patient. I consider myself a Spring expert and it still took me a few days to get things fully working the way I wanted. Note that there is actually VERY LITTLE code you end up writing, but getting the small amount of code exactly right is what’s difficult.
Simple as 1,2,3 ...
Just change a little my OAuth2 server to accept oauth/authorize method.
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers()
.antMatchers("/login", "/oauth/authorize")
.and()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin()
.permitAll();
}
and create a custom login form. Now all clients (web applications) can login into it.
Here you can find a sample client and a more details: http://www.baeldung.com/sso-spring-security-oauth2
Also you can check my entire server and client at my github repo:
https://github.com/icemagno/geoinfra/cerberus
and
https://github.com/icemagno/geoinfra/atlas
It is in pt_BR

How to invoke a listener or interceptor in #CacheEvict

I have a requirement to invoke some functionality when #CacheEvict is being called. Is there a way to call a listener or interceptor to be invoked in Spring #CacheEvict?
Typically, this is very "cache provider" specific since no 2 cache providers have the same capabilities.
For instance, I primarily work with In-Memory Data Grid (IMDG) technology like Pivotal GemFire and the OSS version Apache Geode. Both, of which, can be used as a "caching provider" in Spring's Cache Abstraction. With GemFire/Geode, you can register a o.a.g.cache.CacheListener callback on the GemFire/Geode Region (essentially a java.util.Map) that is backing the Spring Cache interface, and used in Spring's Caching infrastructure as the "Adapter" to the backing store. As you can see with SD GemFire/Geode provider implementation, the "eviction" triggers a GemFire/Geode Region.remove(key). This eviction can subsequently be captures and handled in the Region's registered CacheListener.afterDestroy(:EntryEvent) callback method.
However, this is just 1 way to handle notifications on evictions in your application.
Of course, as #Borino pointed out, you can leverage Spring's AOP support to "intercept" the cache eviction operation. The advantage of this approach is that it is more generic and reusable across different caching providers.
Although, I would say that you should not be developing a AOP Pointcut expression based on the underlying "caching provider", as #Borino instructed, i.e. ...
execution(* org.springframework.cache.concurrent.ConcurrentMapCache.evic‌​t(..))
This expression ties your AOP Aspect to the ConcurrentMapCache "provider", the default in Spring's Cache Abstraction (and in Spring Boot).
What happens when you use Ehcache, Hazelcast, Redis, GemFire/Geode or multiple combinations of these "providers" in your application?
Rather, you can slightly adjust the AOP Pointcut expression to this...
execution(* org.springframework.cache.Cache.evic‌​t(..))
See here. This is safe because all "caching providers" must supply 2 things: a CacheManager implementation and a Cache implementation for each cache specified in the application. Again, the Cache interface is a "Adapter" to the backing store. Again, see the docs for more details.
There are tradeoffs with either approach. Provider specific solutions generally give your more control capabilities, but using the AOP approach is more reusable. Do what is right for your UC.
Hope this helps.
Cheers!
-John
John's answer is on the right track, but it's important to know that the Cache class is not a Spring managed bean, the CacheManager is.
For this reason, you'd have to pull in additional AspectJ dependencies and do some sort of compile or post-compile weaving to target the Cache.evict method.
i tried injecting cache manager to an aspect and set up my point cuts on methods that cache eviction was necessary like here:
package com.example.aspectdemo.aop;
import com.example.aspectdemo.domain.Customer;
import com.example.aspectdemo.service.CustomerService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Component;
#Component
#Aspect
public class CacheEvictHandler {
public static Logger logger = LoggerFactory.getLogger(CacheEvictHandler.class);
private final CacheManager cacheManager;
private final CustomerService customerService;
public CacheEvictHandler(CacheManager cacheManager, CustomerService customerService) {
this.cacheManager = cacheManager;
this.customerService = customerService;
}
#Pointcut(value = "execution(* com.example.aspectdemo.service.impl.CustomerServiceImpl.save(..))")
public void loggingPointCut() {
}
#AfterReturning(value = "loggingPointCut()", returning = "customer")
public void LoggAfterEviction(JoinPoint joinPoint, Customer customer) throws Throwable {
cacheManager.getCache("customer-cache").clear();// remove cache
logger.info("*** saved customer id : {}", customer.getId());// do what you like here, i added some logs
logger.info("*** after eviction : {}", customerService.findAll());
logger.info("*** cache evicted ***");
}
}
here is where i save:
#Transactional
#Override
public Customer save(Customer customer) {
log.debug("Request to save Customer : {}", customer);
return customerRepository.save(customer);
}

What's wrong with my spring-social ConnectController?

I'm trying to make a Spring Boot app that will connect to Fitbit's api using spring-social. I've (half-way) implemented a ConnectionFactory and it's dependencies for Fitbit, and am trying to consume it from my app. Part of this involves starting up a ConnectController to handle the OAuth2 "dance".
When I try to hit the ConnectController through my browser at http://localhost:8080/connect or http://localhost:8080/connect/fitbit I get redirected to the whitelable error page with the message:
There was an unexpected error (type=Method Not Allowed, status=405).
Request method 'GET' not supported
I don't really understand what I'm seeing, but when I set DEBUG level logging and use some breakpoints it looks like hitting /connect from the browser results in Spring trying to find something called connect/status and hitting /connect/fitbit result in spring trying to find something named /connect/fitbitConnect and then trying to internally make a GET request to /connect/connect/fitbitConnect.
In both cases it looks like the methods on ConnectController corresponding to /connect and /connect/{providerId} get called fine, and then Spring bombs when it goes looking for all that other stuff.
Here is the SocialConfigurer implementation I'm using which creates the ConnectController bean:
#Configuration
#EnableSocial
#PropertySource("${properties.path}/fitbot-service.properties")
public class SpringSocialConfig implements SocialConfigurer{
#Override
public void addConnectionFactories(ConnectionFactoryConfigurer connectionFactoryConfigurer, Environment environment) {
connectionFactoryConfigurer.addConnectionFactory(new FitbitConnectionFactory(
environment.getProperty("fitbit.clientId"),
environment.getProperty("fitbit.clientSecret")
));
}
#Override
public UserIdSource getUserIdSource() {
return new SessionUserIdSource();
}
#Override
public UsersConnectionRepository getUsersConnectionRepository(ConnectionFactoryLocator connectionFactoryLocator) {
return new InMemoryUsersConnectionRepository(connectionFactoryLocator);
}
#Bean
public ConnectController connectController(ConnectionFactoryLocator connectionFactoryLocator, ConnectionRepository connectionRepository) {
return new ConnectController(connectionFactoryLocator, connectionRepository);
}
}
What on earth is going on here? What am I doing wrong?
I believe this to be related to your question regarding GET vs. POST in ConnectController, so you may have already answered this for yourself. Nonetheless, let me clarify why it's looking for connect/status and connect/fitbitConnect.
Those are view names. When you do a GET for /connect, you're asking ConnectController to fetch connection status for all providers and to place it in the model, after which it will forward that model to a view whose logical name is "connect/status". Usually this is a JSP at the path "/connect/status.jsp" or maybe a Thymeleaf template at "/connect/status.html", but it can be any view following the rules of whatever Spring MVC view resolvers are in play.
Likewise, a GET request for /connect/fitbit is asking ConnectController to fetch connection status for the "fitbit" provider and to place that information in the model and forward it on to a view whose name is "/connect/fitbitConnect" (if there isn't a connection) or "/connect/fitbitConnected" (if there is a connection).
Aside from answering your question, may I also request that you tell me more about your FitBit Spring Social provider project? Is it modeled after other community-led Spring Social projects? In other words, is it a standalone extension to Spring Social that others may use? If so, tell me where it is in GitHub and I'll be happy to add it to the "Community Projects" section at http://projects.spring.io/spring-social/.

spring-cloud with RestTemplate//Ribbon/Eureka - retry when server not available

I managed to successfully get my RestTemplate client discover remote service using Eureka and forward calls to it using Ribbon as described in the documentation.
Basically, it was just a matter of adding the following annotations of my Application class and let the magic of Spring-Boot do the rest:
#Configuration
#ComponentScan
#EnableAutoConfiguration
#EnableDiscoveryClient
(PS: you noticed I'm using spring-cloud:1.0.0-SNAPSHOT-BUILD and not 1.0.0.M3 - but this doesn't seem to affect my problem).
When two service instances are started, the rest-template client successfully load balance requests between the two. However, the client won't fallback to the second instance if the first is stopped before the Eureka load balancer notices, instead an exception is thrown.
Hence my question: is there a way to configure the RestTemplate/Ribbon/Eureka stack to automatically retry the call to another instance if the one selected the first place is not available? Zuul proxy and feign clients do this "out of the box" so I believe the library holds the necessary features...
Any idea/hint?
Thx,
/Bertrand
The RestTemplate support on its own does not know how to do any retrying (whereas the Feign client and the proxy support in Spring Cloud does, as you noticed). I think this is probably a good things because it gives you the option to add it yourself. For instance, using Spring Retry you can do it in a simple declarative style:
#Retryable
public Object doSomething() {
// use your RestTemplate here
}
(and add #EnableRetry to your #Configuration). It makes a nice combination with #HystrixCommand (from Spring Cloud / Javanica):
#HystrixCommand
#Retryable
public Object doSomething() {
// use your RestTemplate here
}
In this form, every failure counts towards the circuit breaker metrics (maybe we could change that, or maybe it makes sense to leave it like that), even if the retry is successful.
I couldn't get it to work with both #HystrixCommand and #Retryable, regardless of order of annotations on #Configuration class or on #Retryable method due to order of interceptors. I solved this by creating another class with the matching set of methods and had the #HystrixCommand annotated methods delegate to the corresponding #Retryable method in the second class. You could probably have the two classes implement the same interface. This is kind of a pain in the butt, but until order can be configured, this is all I could come up with. Still waiting on a real solution from Dave Syer and the spring cloud guys.
public class HystrixWrapper {
#Autowired
private RetryableWrapper retryableWrapper;
#HystrixCommand
public Response doSomething(...) {
return retryableWrapper.doSomething(...);
}
}
public class RetryableWrapper {
#Autowired
private RestTemplate restTemplate;
#Retryable
public Response doSomething(...) {
// do something with restTemplate;
}
}

Spring Security with HTTPS on CloudFoundry

I tried to access my application on CloudFoundry with the following configuration in the spring security xml
<intercept-url pattern="/signup*" access="permitAll" requires-channel="https" />
but it gives me error This webpage has a redirect loop
However when I changed it to requires-channel="http" I can see my page normally. In both cases I used https on my application. Is this the expected behavior ?
First of all, taking a step back, this (https://johnpfield.wordpress.com/2014/09/10/configuring-ssltls-for-cloud-foundry/) provides excellent context for the nature of the problem.
The key paragraph being
“The threat model here is that the entry point to the cloud is a high availability, secured proxy server.  Once the traffic traverses that perimeter, it is on a trusted subnet.  In fact, the actual  IP address and port number where the Tomcat application server are running are not visible from outside of the cloud. The only way to get an HTTP request to that port is to go via the secure proxy. This pattern is a well established best practice amongst security architecture practitioners.”
Therefore, we may not want or need SSL all the way down, but read on to see how to avoid the https redirect issue when using Spring Security deployed on Cloud Foundry.
You will have a load balancer, HAProxy or some kind of proxy terminating SSL at the boundary of your Cloud Foundry installation. As a convention, whatever you are using should be configured to set X-Forwarded-For and X-Forwarded-Proto headers. The request header “X-Forwarded-Proto" contains the value http or https depending on the original request and you need to use this header parameter for your security decisions further down the stack.
The cleanest way to do this is at the container level, so that Spring Security behaves the same independent of deployment container. Some typical options to configure this are as follows
1) Tomcat
Tomcat should be configured with a RemoteIPValve as described nicely here
The good news is that the Java buildpack for Cloud Foundry already does this for you as seen here
2) Spring Boot (Embedded Tomcat)
Because Tomcat is embedded, the Tomcat config in the Java buildpack will not be activated (see the buildpack Detection Criterion), and therefore some internal Spring Boot configuration is required. Luckily, it’s pretty trivial to configure as you would expect with Spring Boot and you can switch on Tomcat’s RemoteIPValve as explained here by simply defining
server.tomcat.remote_ip_header=x-forwarded-for
server.tomcat.protocol_header=x-forwarded-proto
Both approaches lead to the same outcome of the Tomcat valve overriding the ServletRequest.isSecure() behaviour so that the application has no knowledge of the usage of any proxying. Note that the valve will only be used when the “X-Forwarded-Proto" header is set.
Alternatively, if you really want to go low-level you can dig into the guts of Spring Security, as demonstrated here. As part of that effort, there are some useful findings on how to make the “X-Forwarded-Proto" header available via the Servlet API for other containers (WebLogic, JBoss, Jetty, Glassfish) shared on the comments of https://github.com/BroadleafCommerce/BroadleafCommerce/issues/424
As an additional note, CloudFlare can also act as the SSL-terminating reverse proxy (this is the recommended approach via PWS as discussed here) and it does indeed forward the relevant headers.
References
https://stackoverflow.com/a/28300485/752167
http://experts.hybris.com/answers/33612/view.html
https://github.com/cloudfoundry/java-buildpack/commit/540633bc932299ef4335fde16d4069349c66062e
https://support.run.pivotal.io/entries/24898367-Spring-security-with-https
http://docs.spring.io/spring-boot/docs/current/reference/html/howto-embedded-servlet-containers.html#howto-use-tomcat-behind-a-proxy-server
I have the same issue when I tried to secure my pages with HTTPS using Spring Security.
From the discussion on CloudFoundry Support, seems they "terminate SSL connections at the router". See "Is it possible to visit my application via SSL (HTTPS)?".
And after more than a year, no further information I can find regarding this issue.
In case it's still useful ... I found this post gave the clue to solve something similar to this.
The problem was the org.springframework.security.web.access.channel.SecureChannelProcessor bean was using ServletRequest.isSecure() to decide whether to accept the connection or redirect, which was getting confused inside the cloud.
The following override to that bean seemed to do the job under BlueMix - not sure if the $WSSC request header will apply to all environments.
#Component
public class ChannelProcessorsPostProcessor implements BeanPostProcessor {
#Override
public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException {
if (bean instanceof SecureChannelProcessor) {
final SecureChannelProcessor scp = (SecureChannelProcessor) bean;
return new ChannelProcessor() {
#Override
public void decide(FilterInvocation invocation,
Collection<ConfigAttribute> config) throws IOException,
ServletException {
HttpServletRequest httpRequest = invocation.getHttpRequest();
// Running under BlueMix (CloudFoundry in general?), the
// invocation.getHttpRequest().isSecure() in SecureChannelProcessor
// was always returning false
if ("https".equals(httpRequest.getHeader("$WSSC"))) {
return;
}
scp.decide(invocation, config);
}
#Override
public boolean supports(ConfigAttribute attribute) {
return scp.supports(attribute);
}
};
}
return bean;
}
#Override
public Object postProcessBeforeInitialization(final Object bean, final String beanName) throws BeansException {
return bean;
}
}

Resources