Spring Security : Basic Http Authentication

Suppose we need to create an API which requires user authentication to access that. Spring security is there to implement this on the fly.

First create your REST service

Service.java


@RestController
@RequestMapping("/api")
public class Service
{
private static final Logger LOGGER = LoggerFactory.getLogger( Service.class );

/**
* Clear the template cache
*
* @return response object with status and message
*/
@ResponseBody
@RequestMapping(value = "/foo", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public Response<String> accessApi()
{
Response<String> returnResponse = null;
try
{

returnResponse = new Response<String>( "", "Successfull", Response.SUCCESS );
}
catch ( Exception )
{
// TODO: handle exception
returnResponse = new Response<String>( "", "Error", Response.ERROR );
LOGGER.error( ex.getMessage() );
}

return returnResponse;
}

}

Now create security config class.


@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
{

@Autowired
MyBasicAuthenticationEntryPoint myBasicAuthenticationEntryPoint;

@Autowired
public void configureGlobal( AuthenticationManagerBuilder auth ) throws Exception
{
auth.inMemoryAuthentication().withUser( "user" ) // #1
.password( "password" ).roles( "USER" );
}

@Override
protected void configure( HttpSecurity http ) throws Exception
{
// @formatter:off
http
.authorizeRequests()
.antMatchers("/api/foo").hasRole("USER")
.anyRequest().permitAll()
.and()
.httpBasic()
.authenticationEntryPoint( myBasicAuthenticationEntryPoint );
// @formatter:on
}

}

Now add bean to MvcConfig class.


@Bean
public MyBasicAuthenticationEntryPoint myBasicAuthenticationEntryPoint()
{
return new MyBasicAuthenticationEntryPoint();
}

Then add SecurityConfig class to WebAppInitializer.


public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer
{
@Override
protected Class<?>[] getRootConfigClasses()
{
return new Class<?>[] {SecurityConfig.class };
}

}

Then add


public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer
{

}

Now create entry point.


import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;

public class MyBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint
{

@Override
public void commence( final HttpServletRequest request, final HttpServletResponse response, final AuthenticationException authException ) throws IOException, ServletException
{
response.setHeader( "Access-Control-Allow-Origin", "*" );
response.setHeader( "Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE" );
response.setHeader( "Access-Control-Max-Age", "3600" );
response.setHeader( "Access-Control-Allow-Headers", "x-requested-with" );

response.addHeader( "WWW-Authenticate", "Basic realm=\"" + getRealmName() + "\"" );
response.setStatus( HttpServletResponse.SC_UNAUTHORIZED );
final PrintWriter writer = response.getWriter();
writer.println( "HTTP Status " + HttpServletResponse.SC_UNAUTHORIZED + " - " + authException.getMessage() );
}

@Override
public void afterPropertiesSet() throws Exception
{
setRealmName( "FooService" );
super.afterPropertiesSet();
}
}

Now redirect to http:localhost/example/api/foo URL will request your credentials.

Angularjs + Spring MVC: Remove # from url

AngularJs is mainly used for developing  Single Page Applications (SPA). So different views are loaded to single html on different user actions. The typical URL of AngularJs application is as following.

Default URL : http://localhost:8080/SampleApp/

User Info : http://localhost:8080/SampleApp/#/User

What if you need to remove hash from url and make it SEO friendly.

You need to change both client side and server side configurations for this.

Client side.

Add following to app.js where you have defined the routing.


$locationProvider.html5Mode(true);

Now set base folder in your index.html

 <base href="/SampleApp/index.html"></base> 

Now add the Server side configuration. Its just adding URL mapping and changing the routing.

 @RequestMapping(value = { "/User" }, method = RequestMethod.GET)
public ModelAndView redirectPage(ModelAndView modelAndView ) throws ServletException, IOException
{
RedirectView view = new RedirectView( "redirect:" + "/" );
view.setExposeModelAttributes( false );
return new ModelAndView( view );
}

 

Fixing Error : SpringMVC apache tomcat catalina installtask not found

While working with SpringMVC, I recently found some issues which are raised when we try to build the application using apache ant. I am using apache tomcat as my servlet container. Here is the build.xml file that i am using.


<?xml version="1.0"?>

<project name="springapp" basedir="." default="usage">
 <property file="build.properties"/>

<property name="src.dir" value="src"/>
 <property name="web.dir" value="war"/>
 <property name="build.dir" value="${web.dir}/WEB-INF/classes"/>
 <property name="name" value="springapp"/>

<path id="master-classpath">
 <fileset dir="${web.dir}/WEB-INF/lib">
 <include name="*.jar"/>
 </fileset>
 <!-- We need the servlet API classes: -->
 <!-- * for Tomcat 5/6 use servlet-api.jar -->
 <!-- * for other app servers - check the docs -->
 <fileset dir="${appserver.lib}">
 <include name="servlet*.jar"/>
 </fileset>
 <pathelement path="${build.dir}"/>
 </path>

<target name="usage">
 <echo message=""/>
 <echo message="${name} build file"/>
 <echo message="-----------------------------------"/>
 <echo message=""/>
 <echo message="Available targets are:"/>
 <echo message=""/>
 <echo message="build --> Build the application"/>
 <echo message="deploy --> Deploy application as directory"/>
 <echo message="deploywar --> Deploy application as a WAR file"/>
 <echo message="install --> Install application in Tomcat"/>
 <echo message="reload --> Reload application in Tomcat"/>
 <echo message="start --> Start Tomcat application"/>
 <echo message="stop --> Stop Tomcat application"/>
 <echo message="list --> List Tomcat applications"/>
 <echo message=""/>
 </target>

<target name="build" description="Compile main source tree java files">
 <mkdir dir="${build.dir}"/>
 <javac destdir="${build.dir}" source="1.5" target="1.5" debug="true"
 deprecation="false" optimize="false" failonerror="true">
 <src path="${src.dir}"/>
 <classpath refid="master-classpath"/>
 </javac>
 </target>

<target name="deploy" depends="build" description="Deploy application">
 <copy todir="${deploy.path}/${name}" preservelastmodified="true">
 <fileset dir="${web.dir}">
 <include name="**/*.*"/>
 </fileset>
 </copy>
 </target>

<target name="deploywar" depends="build" description="Deploy application as a WAR file">
 <war destfile="${name}.war"
 webxml="${web.dir}/WEB-INF/web.xml">
 <fileset dir="${web.dir}">
 <include name="**/*.*"/>
 </fileset>
 </war>
 <copy todir="${deploy.path}" preservelastmodified="true">
 <fileset dir=".">
 <include name="*.war"/>
 </fileset>
 </copy>
 </target>

<!-- ============================================================== -->
<!-- Tomcat tasks - remove these if you don't have Tomcat installed -->
<!-- ============================================================== -->

<path id="catalina-ant-classpath">
 <!-- We need the Catalina jars for Tomcat -->
 <!-- * for other app servers - check the docs -->
 <fileset dir="${appserver.lib}">
 <include name="catalina-ant.jar"/>
 </fileset>
 </path>

<taskdef name="install" classname="org.apache.catalina.ant.InstallTask">
 <classpath refid="catalina-ant-classpath"/>
 </taskdef>
 <taskdef name="reload" classname="org.apache.catalina.ant.ReloadTask">
 <classpath refid="catalina-ant-classpath"/>
 </taskdef>
 <taskdef name="list" classname="org.apache.catalina.ant.ListTask">
 <classpath refid="catalina-ant-classpath"/>
 </taskdef>
 <taskdef name="start" classname="org.apache.catalina.ant.StartTask">
 <classpath refid="catalina-ant-classpath"/>
 </taskdef>
 <taskdef name="stop" classname="org.apache.catalina.ant.StopTask">
 <classpath refid="catalina-ant-classpath"/>
 </taskdef>

<target name="install" description="Install application in Tomcat">
 <install url="${tomcat.manager.url}"
 username="${tomcat.manager.username}"
 password="${tomcat.manager.password}"
 path="/${name}"
 war="${name}"/>
 </target>

<target name="reload" description="Reload application in Tomcat">
 <reload url="${tomcat.manager.url}"
 username="${tomcat.manager.username}"
 password="${tomcat.manager.password}"
 path="/${name}"/>
 </target>

<target name="start" description="Start Tomcat application">
 <start url="${tomcat.manager.url}"
 username="${tomcat.manager.username}"
 password="${tomcat.manager.password}"
 path="/${name}"/>
 </target>

<target name="stop" description="Stop Tomcat application">
 <stop url="${tomcat.manager.url}"
 username="${tomcat.manager.username}"
 password="${tomcat.manager.password}"
 path="/${name}"/>
 </target>

<target name="list" description="List Tomcat applications">
 <list url="${tomcat.manager.url}"
 username="${tomcat.manager.username}"
 password="${tomcat.manager.password}"/>
 </target>

<!-- End Tomcat tasks -->

</project>

And here is the build.properties file.

# Ant properties for building the springapp

appserver.home=C:/apache-tomcat-7.0.27
# for Tomcat 5 use $appserver.home}/server/lib
# for Tomcat 6 use $appserver.home}/lib
appserver.lib=${appserver.home}/lib

deploy.path=${appserver.home}/webapps

tomcat.manager.url=http://localhost:8080/manager
tomcat.manager.username=tomcat
tomcat.manager.password=s3cret

But this gave me the above error mentioned in the topic of this post. And here is the way to solve it. Change this t


<taskdef name="install" classname="org.apache.catalina.ant.InstallTask">
 <classpath refid="catalina-ant-classpath"/>
 </taskdef>

into this.


<taskdef name="install" classname="org.apache.catalina.ant.DeployTask">
<classpath refid="catalina-ant-classpath"/>
</taskdef>

The reason is that the installTask class has been outdated. This might be OK with older Tomcat versions. But not with the new versions. 🙂 🙂

Handling static content in Spring MVC

Since Spring MVC is built in framework, there is an specific way to deal with it in some scenarios. Adding the static content like css,js, images is little bit tricky with spring mvc. Before adding these resources, there should be an specific folder structure to it. It should be as follows.

src/
 springmvc/
  java/
   HomeController.java
WebContent/
  resources/
   img/
    image.jpg
  WEB-INF/
    jsp/
      index.jsp
    web.xml
    mvc-dispatcher-servlet.xml

Or as follows.

Everything you need to be static should be kept inside the webapp/resources folder. Now add the configuration to the mvc-dispatcher servlet.xml. Finally it should be like this.


<?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:mvc="http://www.springframework.org/schema/mvc"
 xmlns:context="http://www.springframework.org/schema/context"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
 http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

<context:component-scan base-package="com.supun.springwater.controller" />
 <mvc:resources mapping="/resources/**" location="/resources/" />

 <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
 <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"></bean>
 <bean id="viewResolver"
 class="org.springframework.web.servlet.view.InternalResourceViewResolver">
 <property name="viewClass"
 value="org.springframework.web.servlet.view.JstlView" />
 <property name="prefix">
 <value>/WEB-INF/pages/</value>
 </property>
 <property name="suffix">
 <value>.jsp</value>
 </property>
 </bean>

</beans>

Now link the static content to ur application as follows.


<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<link type="image/x-icon" href="./images/favicon.ico" rel="shortcut icon" lang="en"/>
 <title>Home</title>
<link href="<c:url value="/resources/css/view.css" />" rel="stylesheet" type="text/css" />
<link href="<c:url value="/resources/css/gh-buttons.css" />" rel="stylesheet" type="text/css" />

Now add the dependencies for JSTL in your pom.xml as follows.


<!-- standard.jar -->
 <dependency>
 <groupId>taglibs</groupId>
 <artifactId>standard</artifactId>
 <version>1.1.2</version>
 </dependency>

 <!-- JSTL -->
 <dependency>
 <groupId>javax.servlet</groupId>
 <artifactId>jstl</artifactId>
 <version>1.1.2</version>
 </dependency>

Now clean the project and reimport to eclipse using following commands.

mvn eclipse:clean & mvn eclipse:eclipse -Dwtpversion=2.0 . Then run the application in your application server.