Writing Unit Tests for Oauth in spring boot framework - spring-mvc

I aim to write unit test for oauth - check if user name and token was correct.
The search led me to this artical Faking OAuth SSO
For now, I am following strategy #1.
Following is the piece of code for which I need to figure out dependencies they haven't mentioned directly.
#Test
public void testGetAuthenticationInfo() throws Exception {
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
.apply(springSecurity())
.build();
mockMvc.perform(MockMvcRequestBuilders.get("/api/token")
.with(authentication(getOauthTestAuthentication()))
.sessionAttr("scopedTarget.oauth2ClientContext", getOauth2ClientContext()))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$.username").value("bwatkins"))
.andExpect(jsonPath("$.token").value("my-fun-token"));
}
I managed to arrange for webApplicationContext as below -
#Autowired
private WebApplicationContext webApplicationContext;
For springSecurity() method, I am unable to get the dependency right. Whatever I searched for led me to believe that importing org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.* will get me the method but I am unable to get the pom dependency right.
Question 1: Can anybody help me with getting the dependency right?
Question 2: for such a standard thing as OAuth, isn't there a standard spring boot test package that should just require configuration to test if oauth is working fine or not

This was an issue earlier as mentioned in the issues of spring-security github. It took some time to figure out the correct version which is 4.0.2.RELEASE
https://github.com/spring-projects/spring-security/issues/3861
Adding following in pom.xml fixed the issue.
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<version>4.0.2.RELEASE</version>
</dependency>

Related

TestRestTemplate and spring security

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()

How to store files uploaded from client machine to jboss standalone directory?

I have requirement to store files uploaded (using spring mvc) from client machine to jboss standalone directory .Give step by step solution
I would give the community project called Spring Content a try. This project makes it very easy to handle files by injecting the service and controller implementations for you (so that you don't need to write them yourself).
Adding it would look something like this:
pom.xml (assuming maven. Spring boot starters also available)
<!-- Java API -->
<!-- just change this depdendency if you want to store somewhere else -->
<dependency>
<groupId>com.github.paulcwarren</groupId>
<artifactId>spring-content-fs</artifactId>
<version>0.8.0</version>
</dependency>
<!-- REST API -->
<dependency>
<groupId>com.github.paulcwarren</groupId>
<artifactId>spring-content-rest</artifactId>
<version>0.8.0</version>
</dependency>
StoreConfig.java
#Configuration
#EnableFilesystemStores
#Import(RestConfiguration.class)
public class StoreConfig {
#Bean
FileSystemResourceLoader fileSystemResourceLoader() throws IOException {
return new FileSystemResourceLoader(new File("/path/to/uploaded/files").getAbsolutePath());
}
}
FileStore.java
#StoreRestResource(path="files")
public interface FileStore extends Store<String> {
}
And that's it. The FileStore is essentially a generic Spring ResourceLoader. The spring-content-fs dependency will cause Spring Content to inject a filesystem-based implementation. The spring-content-rest dependency will cause Spring Content to also inject an implementation if an #Controller that forwards HTTP requests onto the methods of the FileStore service.
So you will now have a fully functional (POST, PUT, GET, DELETE) REST-based file service at /files that will use your FileStore to retrieve (and store) files in /path/to/uploaded/files on your jboss server.
So:
curl --upload-file some-image.jpg /files/some-image.jpg
will upload some-image.jpg and store it in /path/to/uploaded/files on your server.
And:
curl /files/some-image.jpg
would retrieve it again.
HTH
The injected controller also supports video streaming too, in case that is useful.
With this you could also remove all of your controller and service code as it is no longer required. Plus, as Spring Content is an abstraction over storage, in future, you could also shift to any of the other storage mediums supported by Spring Content; S3 for example.

spring security: #EnableResourceServer vs oauth2ResourceServer()

What is the difference between using #EnableResourceServer and using HttpSecurity.oauth2ResourceServer()? Why should I use one or the other?
#EnableResourceServer is an annotation from the Spring Security OAuth project that is being replaced by new OAuth features in Spring Security 5. In essence, it loads ResourceServerConfiguration, which extends WebSecurityConfigurerAdapter and configures it, creating a filter chain that gives your application resource server functionality. Check out the docs or its source code for more info.
http.oauth2ResourceServer() is in the current Spring Security 5 reference and is the way to go. It creates a BearerTokenAuthenticationFilter that intercepts requests, extracts any Bearer Tokens and attempts to authenticate. For more details, check out the source code for the filter or for the configurer that creates the filter.

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/.

Can't get SessionContext on EJB

I can't get a SessionContext object on an EJB. I've tried all the options suggested on 4 Ways to Get EJBContext in EJB 3 and none of them worked. For example, the following code in my project...
#Stateful
public class SecurityService {
#Resource
private SessionContext context;
#PostConstruct
public void init() {
}
}
... generates the following exception during deploy:
[#|2012-02-28T14:35:02.805-0300|SEVERE|glassfish3.1.1|javax.enterprise.system.core.com.sun.enterprise.v3.server|_ThreadID=18;_ThreadName=admin-thread-pool-4848(5);|The log message is null.
java.lang.NullPointerException
at com.sun.appserv.connectors.internal.api.AppSpecificConnectorClassLoaderUtil.detectResourceInRA(AppSpecificConnectorClassLoaderUtil.java:266)
at com.sun.appserv.connectors.internal.api.AppSpecificConnectorClassLoaderUtil.processDescriptorForRAReferences(AppSpecificConnectorClassLoaderUtil.java:211)
at com.sun.appserv.connectors.internal.api.AppSpecificConnectorClassLoaderUtil.processDescriptorForRAReferences(AppSpecificConnectorClassLoaderUtil.java:130)
at com.sun.appserv.connectors.internal.api.AppSpecificConnectorClassLoaderUtil.detectReferredRARs(AppSpecificConnectorClassLoaderUtil.java:118)
at com.sun.appserv.connectors.internal.api.ConnectorClassLoaderServiceImpl.getConnectorClassLoader(ConnectorClassLoaderServiceImpl.java:111)
at com.sun.enterprise.v3.server.ClassLoaderHierarchyImpl.getConnectorClassLoader(ClassLoaderHierarchyImpl.java:117)
If I remove the #Resource annotation it deploys, but does not work (i've tried with JNDI and the other methods cited before).
I'm using Glassfish 3.1.1, and my project is JSF with CDI and EJB locally to services with JPA. I've tried injecting SessionContext on CDI beans but received the same errors. My EJB are configured with annotations, and my beans.xml have no configurations (but exists).
One strange thing is that with JNDI lookup I've managed to get an object of type SessionContextImpl on path java:/comp/EJBContext on the #PostConstruct init() method. BUT, it goes to null as soon as another EJB method is called (?) and it does not contain user's roles data (a call to isCallerInRole() throws an exception). Also, it is not an EJBContext object.
I'm packaging everything in a WAR using Maven, and the dependency of Java EE is marked as provided, as the following shows:
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>6.0</version>
<scope>provided</scope>
</dependency>
It seems to me that there is no SessionContext (EJBCOntext) been provided by the container at all. I don't know even if that is possible, and I have no idea on how to solve this.
Please, If you have ANY idea about this, I'll be glad to hear it. Thank you.
If your Principal has logged in using j_security_check, you can inject the SecurityContext in an EJB, or in a ManagedBean, and retrieve Principal's and role's information like this:
#Context private SecurityContext context;
....
boolean isInRole = context.isUserInRole("A role");
Principal p = context.getUserPrincipal();
Well, I've upgraded to Glassfish 3.1.2 and the problem was solved. Now I can inject javax.ejb.SessionContext as expected.
Special thanks to #perissf for the help.

Resources