backgroung headerTechFirst header

Secure Spring MVC RESTful Application using OAuth2

Spring MVC

Spring is a robust framework and used by millions of developer around the world. Spring has many modules which serves, variety of purpose for many different use cases. Security is always the prime consideration for any application, and spring provides powerful security features through OAuth2 module.

There are other product/frameworks available, which can help in achieving security considerations, e.g. Ping Federation, CA Siteminder, SAML, and Sentry etc.  Though these are primarily used for very large implementation and involve cost. Generally big organizations prefer to choose this route for standardization.

In this blog, we will share steps to implement security using OAuth2 module. This would provide equal security benefit with advantage of being open source and flexible.

It is highly recommended to always follow OWASP guidelines for security.

Let’s follow below steps for implementation using OAuth2 in-memory authentication:

Step 1: Create file ProtectedResource.java

package com.api.resources;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(“/protected/demo”)

public class ProtectedResource {
      @RequestMapping(value = “/{name}”, method = RequestMethod.GET)
      public String getGreeting(@PathVariable String name) {
               String result = “Hello ” + name+”\nThis is a protedted page.”;
               return result;
      }
}

Step 2: Create file UnprotectedResource.java

package com.api.resources;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(“/unprotecteddemo”)
public class UnprotectedResource {
      @RequestMapping(value = “/{name}”, method = RequestMethod.GET)
       public String getGreeting(@PathVariable String name) {
               String result = “Hello ” + name +”\n This is a unprotected page.”;
               return result;
       }
}

Step 3: Create file GuestServiceImpl.java

package com.api.test;

import java.util.ArrayList;
import java.util.List;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.ClientRegistrationException;
import org.springframework.security.oauth2.provider.NoSuchClientException;
import org.springframework.security.oauth2.provider.client.BaseClientDetails;

public class GuestServiceImpl implements ClientDetailsService {
      private String id;
      private String secretKey;

      @Override
      public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
            if (clientId.equals(id)) {
                  List<String> authorizedGrantTypes = new ArrayList<String>();
                  authorizedGrantTypes.add(“password”);
                  authorizedGrantTypes.add(“refresh_token”);
                  authorizedGrantTypes.add(“client_credentials”);
                   BaseClientDetails clientDetails = new BaseClientDetails();
                  clientDetails.setClientId(id);
                  clientDetails.setClientSecret(secretKey);
                  clientDetails.setAuthorizedGrantTypes(authorizedGrantTypes);
                  return clientDetails;
            } else {
                  throw new NoSuchClientException(“No client recognized with id: “+ clientId);}
            }

      public String getId() {
            return id;
      }

      public void setId(String id) {
            this.id = id;
      }

      public String getSecretKey() {
            return secretKey;
      }

      public void setSecretKey(String secretKey) {
            this.secretKey = secretKey;
      }
}

Step 4: Create file UserAuthenticationProvider.java

package com.api.test;

import java.util.ArrayList;
import java.util.List;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;

public class UserAuthenticationProvider implements AuthenticationProvider{
      @Override
       public Authentication authenticate(Authentication authentication) throws AuthenticationException {
               String user=authentication.getPrincipal().toString();
               String pwd=authentication.getCredentials().toString();
               //PUT Auth Bean here
               boolean result=user.equals(“myuser”) && pwd.equals(“mypassword”);
               if (result) {
                     List<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
                     UserAuthenticationToken auth = new UserAuthenticationToken(authentication.getPrincipal(),
                     authentication.getCredentials(), grantedAuthorities);
                     return auth;
               } else {
                     throw new BadCredentialsException(“Bad User Credentials.”);
               }
       }

       @Override
       public boolean supports(Class<?> type) {
               return true;
}
}

Step 5: Create file UserAuthenticationToken.java

package com.api.test;

import java.util.Collection;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;

public class UserAuthenticationToken extends AbstractAuthenticationToken {
       private static final long serialVersionUID = -1092219614309982278L;
       private final Object principal;
       private Object credentials;

       public UserAuthenticationToken(Object principal, Object credentials,
               Collection<? extends GrantedAuthority> authorities) {
               super(authorities);
               this.principal = principal;
               this.credentials = credentials;
               super.setAuthenticated(true);
       }

       public Object getCredentials() {
               return this.credentials;
        }

        public Object getPrincipal() {
               return this.principal;
         }
}

Step 6: Create file applicationContext.xml

<?xml version=”1.0″ encoding=”UTF-8″ ?>
<beans xmlns=”http://www.springframework.org/schema/beans”
  xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns:oauth=”http://www.springframework.org/schema/security/oauth2″
  xmlns:sec=”http://www.springframework.org/schema/security”
xmlns:mvc=”http://www.springframework.org/schema/mvc”
xmlns:
context=”http://www.springframework.org/schema/context”

  xsi:schemaLocation=”http://www.springframework.org/schema/security/oauth2
http://www.springframework.org/schema/security/spring  security-oauth2-1.0.xsd
  http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
  http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
  http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd”>
  <context:component-scan base-package=”com.api” />
  <sec:http pattern=”/oauth/token” create-session=”stateless” authentication-manager-ref=”authenticationManager”>
        <sec:intercept-url pattern=”/oauth/token” access=”IS_AUTHENTICATED_FULLY” />
        <sec:anonymous enabled=”false” />
        <sec:http-basic entry-point-ref=”clientAuthenticationEntryPoint” />
        <sec:custom-filter ref=”clientCredentialsTokenEndpointFilter” before=”BASIC_AUTH_FILTER” />
        <sec:access-denied-handler ref=”oauthAccessDeniedHandler” />
  </sec:http>
  <sec:http pattern=”/protected/**” create-session=”never” entry-point-ref=”oauthAuthenticationEntryPoint”>
        <sec:anonymous enabled=”false” />
        <sec:intercept-url pattern=”/protected/**” method=”GET” access=”IS_AUTHENTICATED_FULLY” />
        <sec:custom-filter ref=”resourceServerFilter” before=”PRE_AUTH_FILTER” />
        <sec:access-denied-handler ref=”oauthAccessDeniedHandler” />
  </sec:http>
  <bean id=”oauthAuthenticationEntryPoint”
        class=”org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint”>
  </bean>
  <bean id=”clientAuthenticationEntryPoint”
        class=”org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint”>
        <property name=”realmName” value=”springsec/client” />
        <property name=”typeName” value=”Basic” />
  </bean>
  <bean id=”oauthAccessDeniedHandler”
        class=”org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler”>
  </bean>
  <bean id=”clientCredentialsTokenEndpointFilter”
        class=”org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter”>
        <property name=”authenticationManager” ref=”authenticationManager” />
  </bean>
  <sec:authentication-manager alias=”authenticationManager”>
        <sec:authentication-provider user-service-ref=”clientDetailsUserService” />
  </sec:authentication-manager>
  <bean id=”clientDetailsUserService”
        class=”org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService”>
        <constructor-arg ref=”clientDetails” />
  </bean>
  <bean id=”clientDetails” class=”com.api.test.GuestServiceImpl”>
        <property name=”id” value=”samplecompanyid” />
        <property name=”secretKey” value=”samplecompanykey” />
  </bean>
  <sec:authentication-manager id=”userAuthenticationManager”>
        <sec:authentication-provider ref=”customUserAuthenticationProvider” />
  </sec:authentication-manager>
  <bean id=”customUserAuthenticationProvider”
        class=”com.api.test.UserAuthenticationProvider”>
  </bean>
  <oauth:authorization-server client-details-service-ref=”clientDetails” token-services-ref=”tokenServices”>
  <oauth:authorization-code />
  <oauth:implicit/>
  <oauth:refresh-token/>
  <oauth:client-credentials />
  <oauth:password authentication-manager-ref=”userAuthenticationManager”/>
  </oauth:authorization-server>
  <oauth:resource-server id=”resourceServerFilter” resource-id=”springsec” token-services-ref=”tokenServices” />
  <bean id=”tokenStore”  class=”org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore” />
  <bean id=”tokenServices”
        class=”org.springframework.security.oauth2.provider.token.DefaultTokenServices”>
        <property name=”tokenStore” ref=”tokenStore” />
        <property name=”supportRefreshToken” value=”true” />
        <property name=”accessTokenValiditySeconds” value=”120″></property>
        <property name=”clientDetailsService” ref=”clientDetails” />
  </bean>
  <mvc:annotation-driven />
  <mvc:default-servlet-handler />
  <context:annotation-config/>
</beans>

Step 7: Create file web.xml

<?xml version=”1.0″ encoding=”UTF-8″?>
<web-app xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns=”http://java.sun.com/xml/ns/javaee” xsi:schemaLocation=”http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd” id=”WebApp_ID” version=”3.0″>
    <display-name>SpringSecBlog</display-name>
    <session-config>
        <session-timeout>
                 30
        </session-timeout>
    </session-config>
    <servlet>
         <servlet-name>api</servlet-name>
         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
         <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
         <servlet-name>api</servlet-name>
         <url-pattern>/</url-pattern>
    </servlet-mapping>
    <listener>
          <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <filter>
          <filter-name>springSecurityFilterChain</filter-name>
          <filter-class>
                 org.springframework.web.filter.DelegatingFilterProxy
           </filter-class>
    </filter>
    <filter-mapping>
            <filter-name>springSecurityFilterChain</filter-name>
            <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

Step 8: Create file pom.xml as below and build maven project and finally deploy on tomcat 7

<project xmlns=”http://maven.apache.org/POM/4.0.0″ xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation=”http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd”>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.api</groupId>
    <artifactId>SpringSecBlog</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>SpringSecBlog</name>
    <dependencies>
        <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-core</artifactId>
             <version>4.0.6.RELEASE</version>
        </dependency>
        <dependency>
             <groupId>org.springframework.security.oauth</groupId>
             <artifactId>spring-security-oauth2</artifactId>
             <version>2.0.3.RELEASE</version>
        </dependency>
        <dependency>
              <groupId>javax</groupId>
              <artifactId>javaee-web-api</artifactId>
              <version>6.0</version>
              <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
       <sourceDirectory>src</sourceDirectory>
       <plugins>
              <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.1</version>
                    <configuration>
                          <source>1.7</source>
                          <target>1.7</target>
                    </configuration>
              </plugin>
              <plugin>
                    <artifactId>maven-war-plugin</artifactId>
                    <version>2.3</version>
                    <configuration>
                          <warSourceDirectory>WebContent</warSourceDirectory>
                         <failOnMissingWebXml>false</failOnMissingWebXml>
                    </configuration>
              </plugin>
       </plugins>
    </build>
</project>

Here is the reference project structure (in eclipse) created as per above steps:

Step 9: Access unprotected page using below URL on REST client like postman:

http://localhost:8090/SpringSecBlog/unprotecteddemo/chandan

Step 10: Access protected page using below URL on REST client like postman:

http://localhost:8090/SpringSecBlog/protected/demo/chandan

2
Published on: 21 June, 2017

TAGS

4,840 views

11 Replies to “Secure Spring MVC RESTful Application using OAuth2”

    • Pep
      Pep

      Hi,

      Glad to know that you liked the blog article. You can subscribe to our blog posts and stay updated with the latest tech trends. You can also reach out to us on marketing@vfirst.com for any queries or information.

      Thanks
      Team ValueFirst

  1. Anonymous

    I’ll have to say that you are doing a very great job in writing good
    articles like this. I’ve bookmarked you and will
    gladly follow your upcoming articles.
    Thank you very much.

    • Pep
      Pep

      Hi,

      Thanks for writing such a wonderful review. Happy to know that you loved reading our articles and have bookmarked the blog! The main aim of our blog is to share maximum information with the users and help them understand how they can leverage the best of marketing communication channels to enhance customer engagement. For any further information do connect with us at marketing@vfirst.com.

      Thanks
      Team ValueFirst

  2. Anonymous

    I know this site presents quality depending posts and additional material, is there any other site
    which provides these stuff in quality?

    • Pep
      Pep

      Hi,

      Thanks for your comment. Happy to know that you liked the quality of our blog content! You can now get our latest blog updates straight to your inbox by hitting subscribe button on the blog. For any further information do connect with us at marketing@vfirst.com.

      Thanks
      Team ValueFirst

  3. Anonymous

    Usually I do not read article on blogs, however I wish to say that this write-up very forced me to take a look at and do it! Your writing style has been amazed me.
    Thanks, very nice article.

    • Pep
      Pep

      Hi,

      Thanks for your amazing comment! It feels great to know that you liked the article so much. You can also subscribe to our blog for more such articles. For more information do connect with us on marketing@vfirst.com.

      Thanks
      Team ValueFirst

  4. Anonymous

    Thank you for every other informative web site.
    Where else mmay just I am getting that kind of info written in such
    a perfect means?

  5. Anonymous

    It’s amazing designed for me to have a web site, which is useful
    in favor of my know-how. thanks admin

Leave a Reply

Your email address will not be published. Required fields are marked *