Adding Http Basic Auth to RESTful Services in Java and Spring
Join the DZone community and get the full member experience.
Join For FreeAdding basic http authentication to a set of Spring MVC based services is very simple. This tutorial teaches how to quickly setup authentication by keeping a set of usernames, passwords and roles in a spring configuration file and associating URL patterns with these for the framework to determine if a user is authorized or not. For more robust authentication and authorization where you might be using a Directory server and LDAP, additional configurations are required which are not being discussed in this post.
In this tutorial, I will work with the assumption that you already have a running application built with Spring MVC. If you do, there really are only two steps involved. Let’s start:
1. Adding Dependencies
The first thing you need to do is get the relevant spring security modules. Add these dependencies to your pom.xml
<dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>${org.springframework.version}</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>${org.springframework.version}</version> <type>jar</type> <scope>compile</scope> </dependency>
2. Modifying the web.xml
The first thing we do is to add a DelegatingFilterProxy
filter. This is a standard servlet filter that delegates responsibility
to a Spring bean. In other words, you can provide spring support for
servlet filters via the DelegatingFilterProxy. In our example, we will use the DelegatingFilterProxy
to delegate authentication (and eventually authorization)
responsibilities to a spring bean. Add the following XML to your
web.xml.
<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> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:security-context.xml</param-value> </context-param>
3. Creating the security context xml and placing it in the classpath
In line 16 of the web.xml snippet above,
I refer to a file security-context.xml. This gets loaded into the
spring context at application startup and consists of our security
configurations. This is what this file looks like:
<?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:security="http://www.springframework.org/schema/security" 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/security http://www.springframework.org/schema/security/spring-security-3.0.xsd"> <security:http auto-config='true'> <security:intercept-url pattern="/logs/**" access="ROLE_USER, ROLE_ADMIN"/> <security:intercept-url pattern="/logviewer.html" access="ROLE_USER, ROLE_ADMIN"/> <security:intercept-url pattern="/qr/**" access="ROLE_USER, ROLE_ADMIN"/> <!-- security:intercept-url pattern="/sms/**" access="ROLE_USER, ROLE_ADMIN"/--> <security:intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY"/> <security:http-basic /> </security:http> <security:authentication-manager> <security:authentication-provider> <security:user-service> <security:user name="username1" password="password1" authorities="ROLE_USER" /> <security:user name="username2" password="password2" authorities="ROLE_USER, ROLE_ADMIN" /> </security:user-service> </security:authentication-provider> </security:authentication-manager> </beans>
Remember to add namespace and xsd declarations for security (lines 4 and 9). From lines 13 to 17, we provide mappings of URLs against roles. The ROLE_ settings are the roles within the application where these could be roles defined in a database or groups in active directory etc. IS_AUTHENTICATED_ANONYMOUSLY is used to specify that you can get in anonymously. Therefore the above settings allow all requests to be served anonymously without authentication except the 3 mentioned that require authentication. The intercepts are evaluated top-down which means that if <security:intercept-url pattern=”/**” access=”IS_AUTHENTICATED_ANONYMOUSLY”/> was first in the list, all requests would go through.
4. Calling the service
Let’s see what happens when we call a URL that is configured to be authenticated. We get a pop up that asks for username and password.
In case you provide an invalid user name and/or password, you get a HTTP 415 error
Lets look at the HTTP request header when we have a successful login
You will notice in the image above that there is a header attribute Authorization with value Basic dXNlcm5hbWUxOnBhc3N3b3JkMQ==
If we decode this using any Base64 decoder, we get username1:password1.
You can see that HTTP basic authentication simply takes your username
and password, concatenates them as username:password and then encodes
them in Base64 and sends it over the wire.
The bottom line is that HTTP basic auth is very easy to implement and better than no security at all but is vulnerable and should be replaced with more robust mechanism like Digest Authentication which I may discuss in a future post.
Published at DZone with permission of Faheem Sohail, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments