Category Archives: Spring Security

Spring Security

Sample of Spring Security and CAS (Single Signon)

For people in hurry get the code from Github.

In continuation of my earlier blog on spring-test-mvc junit testing Spring Security layer with InMemoryDaoImpl, in this blog I will be doing the following,

  • Run a sample Jasig, deployed in tomcat instance
  • Run a sample Spring security Calendar application with uses single signon to do authentication and authorization of the application

Setup of Central Authorization Service (CAS): Jasig

Central Authorization Service (CAS) is a Single Signon application used to authenticate and authorize an application for centralized user access control. Jasig is an opensource CAS application. In order for Jasig to work we need to enable SSL.

<Connector SSLEnabled="true"
maxThreads="150"
port="8443"
protocol="HTTP/1.1"
scheme="https"
secure="true"
sslProtocol="TLS"
keystoreFile="${catalina.base}/conf/tomcat.keystore"
keystorePass="changeit"
truststoreFile="${catalina.base}/conf/tomcat.truststore"
trustStorePass="changeit"/>

Run the Calendar application against CAS

Build the code from spring-security-cas project using maven command “mvn clean package” and deploy the war file in the target folder into <Tomcat home>/webapps folder. Start the Tomcat instance. If you go to the calendar home page @ https://localhost:8443/calendar, you will see the webpage as below,

spring-security calendar application

spring-security calendar application

When you click on My Events we get the below Jasig page,

CAS jasig

CAS jasig

Enter login/password as user1@example.com/user1. You will get the access to your events.

When you log out, it will again redirect to Jasig logout page.

What is happening under the hood on Jasig side

Under the hood, Jasig CAS server is configured to work with inmemory LDAP as below,

<sec:ldap-server id="contextSource" ldif="classpath:ldif/calendar.ldif" root="dc=jbcpcalendar,dc=com" />

And mapping of LDAP attributes to CAS attributes happens in the below bean definition,

<!--
Bean that defines the attributes that a service may return.  This example uses the Stub/Mock version.  A real implementation
may go against a database or LDAP server.  The id should remain "attributeRepository" though.
-->
<bean id="attributeRepository">
<property name="contextSource" ref="contextSource"/>
<property name="requireAllQueryAttributes" value="true"/>
<property name="baseDN" value="ou=Users"/>
<property name="queryAttributeMapping">
<map>
<entry key="username" value="uid"/>
</map>
</property>
<property name="resultAttributeMapping">
<map>
<entry key="cn" value="FullName"/>
<entry key="sn" value="LastName"/>
<entry key="description" value="role"/>
</map>
</property>
</bean>

Check the deployerConfigContext.xml under webapp/WEB-INF folder in the project for more details

What is happening under the hood on Calendar application

In the web.xml we need to include a SingleSignon listener as below,

<listener>
<listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
</listener>

We need to define a casAuthProvider bean and include it in the authentication-manager in the security config as below,

<authentication-manager alias="authenticationManager">
<authentication-provider ref="casAuthProvider" />
</authentication-manager>

Refer src\main\webapp\WEB-INF\spring\security-cas.xml file for more details on casAuthProvider bean definition.

Maven dependency for Spring Security with CAS is as below,

<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-cas</artifactId>
<version>3.1.0.RELEASE</version>
<scope>compile</scope>
</dependency>

I hope this blog helped you.

REFERENCE

Spring Security 3.1 by Robert Winch and Peter Mularien

spring-test-mvc junit testing Spring Security layer with Method level Security

For people in hurry get the code from Github.

In continuation of my earlier blog on spring-test-mvc junit testing Spring Security layer with InMemoryDaoImpl, in this blog I will discuss how to use achieve method level access control. Please follow the steps in this blog to setup spring-test-mvc and run the below test case.

mvn test -Dtest=com.example.springsecurity.web.controllers.SecurityControllerTest

The Junit test case looks as below,

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = WebContextLoader.class, value = { "classpath:/META-INF/spring/services.xml",
"classpath:/META-INF/spring/security.xml",
"classpath:/META-INF/spring/mvc-config.xml" })
public class SecurityControllerTest {

@Autowired
CalendarService calendarService;

@Test
public void testMyEvents() throws Exception {
Authentication auth = new UsernamePasswordAuthenticationToken("user1@example.com", "user1");
SecurityContext securityContext = SecurityContextHolder.getContext();
securityContext.setAuthentication(auth);

calendarService.findForUser(0);
SecurityContextHolder.clearContext();
}

@Test(expected = AuthenticationCredentialsNotFoundException.class)
public void testForbiddenEvents() throws Exception {
calendarService.findForUser(0);
}
}
@Test(expected=AccessDeniedException.class)
public void testWrongUserEvents() throws Exception {
Authentication auth = new UsernamePasswordAuthenticationToken("user2@example.com", "user2");
SecurityContext securityContext = SecurityContextHolder.getContext();
securityContext.setAuthentication(auth);

calendarService.findForUser(0);
SecurityContextHolder.clearContext();
}

If you notice, if the user did not login or if the user is trying to access another users information it will throw an exception.

The interface access control is as below,

public interface CalendarService {

@PreAuthorize("hasRole('ROLE_ADMIN') or principal.id == #userId")
List<Event> findForUser(int userId);
}

The PreAuthorize only works on interface so that any implementation that implements this interface has this access control.

I hope this blog helps you. In my next blog I will explain how you integrate Spring Security with Central Authorization Service (CAS) Single Sign On.

REFERENCE

Spring Security 3.1 by Robert Winch and Peter Mularien

spring-test-mvc junit testing Spring Security layer with LDAP

For people in hurry get the code from Github.

In continuation of my earlier blog on spring-test-mvc junit testing Spring Security layer with InMemoryDaoImpl, in this blog I will discuss how to use Spring Security’s LDAP integration.

Please follow the steps in this blog to setup spring-test-mvc and run the below test case,

mvn clean test -Dtest=com.example.springsecurity.web.controllers.Video4LdapProviderControlerTest

The dependency required integrating LDAP is as below,

<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-ldap</artifactId>
<version>3.1.0.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.directory.server</groupId>
<artifactId>apacheds-protocol-ldap</artifactId>
<version>1.5.5</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.directory.shared</groupId>
<artifactId>shared-ldap</artifactId>
<version>0.9.15</version>
<scope>compile</scope>
</dependency>

In this example we used inmemory LDAP configured to work with calendar.ldif for all user/role information. In the real life, there will be a enterprise quality LDAP like Active Director configured with Spring Security. For configuring this in spring security configuration you need to add below code,

<ldap-server id="ldapServer" ldif="classpath:ldif/calendar.ldif" root="dc=jbcpcalendar,dc=com" />

The plumbing for spring-test-mvc to work with LDAP is in the class com.example.springsecurity.web.controllers.util.LdapSecurityRequestPostProcessors. The below code does the magic,

private UsernamePasswordAuthenticationToken authentication(ServletContext servletContext) {
ApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);

FilterBasedLdapUserSearch filterBasedLdapUserSearch = context.getBean(FilterBasedLdapUserSearch.class);

DirContextOperations ldapUserDetails = filterBasedLdapUserSearch.searchForUser(username);

List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(1);
authorities.add(new SimpleGrantedAuthority(ldapUserDetails.getStringAttribute("sn")));

return new UsernamePasswordAuthenticationToken(username, ldapUserDetails.getObjectAttribute("userpassword").toString(),
authorities);
}

spring bean definition for FilterBasedLdapUserSearch is as below,

<bean id="ldapSearch">
<constructor-arg value="ou=users"/> <!-- use-search-base -->
<constructor-arg value="(uid={0})"/> <!-- user-search-filter -->
<constructor-arg ref="ldapServer"/>
</bean>

I hope this blog helped. In my next blog I will be explaining how to integrate Spring Security with Method level access control.

REFERENCE

Spring Security 3.1 by Robert Winch and Peter Mularien

spring-test-mvc junit testing Spring Security layer with JdbcDaoImpl

In continuation of my earlier blog on spring-test-mvc junit testing Spring Security layer with InMemoryDaoImpl, in this blog I will discuss how to use Spring Security’s JdbcDaoImpl class.

In this blog, we will be discussing same usecase and same code base as in this blog, the only difference being for testing this feature you need to run different testcase as below,

mvn clean test -Dtest=com.example.springsecurity.web.controllers.Video3JdbcUserServiceControllerTest

The database schema for user authorization is as below,

create table calendar_users (
id bigint identity,
email varchar(256) not null unique,
password varchar(256) not null,
first_name varchar(256) not null,
last_name varchar(256) not null
);

create table calendar_user_authorities (
id bigint identity,
calendar_user bigint not null,
authority varchar(256) not null,
);

Below is the JDBC configuration to identify the user and his role/authorization to access.

<authentication-manager>
<authentication-provider>
<jdbc-user-service id="userDetailsService"
data-source-ref="dataSource"
users-by-username-query="select email,password,true from calendar_users where email = ?"
authorities-by-username-query="select cua.id, cua.authority from calendar_users cu, calendar_user_authorities cua where cu.email = ? and  cu.id = cua.calendar_user"/>
</authentication-provider>
</authentication-manager>

I hope this blog helped you. In my next blog, I will demo how to use LDAP for Securing an application.

REFERENCE

Spring Security 3.1 by Robert Winch and Peter Mularien

spring-test-mvc junit testing Spring Security layer with InMemoryDaoImpl

For people in hurry here is the code sample and the steps to setup the code.

Spring Security 3.1 is a framework that supports authentication and authorization in Java. Spring MVC has a good integration with Spring Security. In this blog, I will demonstrate how to JUnit test Spring Security layer for a Spring MVC application using spring-test-mvc.

The usecase we use in this blog is a Spring MVC based calendar application, where user can login and enter his events his events. User can see other user events but he cannot change it. An admin user can see other user’s Events as well as change it.

To enable spring-test-mvc, we need to setup spring-test-mvc. As a first setp get the latest code from github. and run the “mvn install” command in the downloaded folder. After that we need to add the below dependency in the pom.xml,

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test-mvc</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
<scope>test</scope>
</dependency>

For a starter I will start writing the JUnit test as below to capture above usecase,

@Before
public void setup() {
mockMvc = MockMvcBuilders.webApplicationContextSetup(this.wac).addFilters(this.springSecurityFilterChain).build();
}

@Test
public void testIndex() throws Exception {
mockMvc.perform(get("/")).andExpect(status().isOk()).andExpect(forwardedUrl("/WEB-INF/views/index.jsp"));
}

@Test
public void testEventsNonAdmin() throws Exception {
mockMvc.perform(get("/events/").with(userDeatilsService("user1@example.com"))).andExpect(status().isForbidden());
}

@Test
public void testEventsAdminLogin() throws Exception {
mockMvc.perform(get("/events/").with(userDeatilsService("admin1@example.com"))).andExpect(status().isOk());
}

@Test
public void testMyEvents() throws Exception {
mockMvc.perform(get("/events/my").with(userDeatilsService("user1@example.com"))).andExpect(status().isOk());
}

@Test
public void testShow() throws Exception {
mockMvc.perform(get("/events/100").with(userDeatilsService("user1@example.com"))).andExpect(status().isOk());
}

@Test
public void testCreateEventForm() throws Exception {
mockMvc.perform(
post("/events/new").param("attendeeEmail", "user1@example.com").param("summary", "krishna").param("description", "whatever")
.param("when", "2012-01-01 01:02").with(userDeatilsService("user1@example.com"))).andExpect(status().isOk())
.andExpect(redirectedUrl("/events/my"));
}

To wire Spring Security with JUnit test you need to do as below,

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = WebContextLoader.class, value = {
"classpath:/META-INF/spring/video1-spring-inmemory-userdetailservice-config/services.xml",
"classpath:/META-INF/spring/video1-spring-inmemory-userdetailservice-config/security.xml",
"classpath:/META-INF/spring/video1-spring-inmemory-userdetailservice-config/mvc-config.xml" })
public class Video1SpringInmemoryUserdetailServiceControllerTest {

The Spring security config file looks as below,

<http pattern="/resources/**" security="none"/>
<http auto-config="true" use-expressions="true" create-session="ifRequired">
<intercept-url pattern="/" access="hasRole('ROLE_ANONYMOUS') or hasRole('ROLE_USER')"/>
<intercept-url pattern="/login/*" access="hasRole('ROLE_ANONYMOUS') or hasRole('ROLE_USER')"/>
<intercept-url pattern="/logout" access="hasRole('ROLE_ANONYMOUS') or hasRole('ROLE_USER')"/>
<intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')"/>
<intercept-url pattern="/events/" access="hasRole('ROLE_ADMIN')"/>
<intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>

<form-login login-page="/login/form"
login-processing-url="/login" username-parameter="username" password-parameter="password"
authentication-failure-url="/login/form?error"/>
<logout logout-url="/logout" logout-success-url="/login/form?logout"/>
</http>

<authentication-manager>
<authentication-provider>
<user-service>
<user name="user1@example.com" password="user1" authorities="ROLE_USER"/>
<user name="admin1@example.com" password="admin1" authorities="ROLE_USER,ROLE_ADMIN"/>
</user-service>
</authentication-provider>
</authentication-manager>

In this configuration there are 2 blocks one is http block that describes authentication and authentication-manager that describes authorization. In this example, for authorization we are using org.springframework.security.core.userdetails.memory.InMemoryDaoImpl helper class. To make this example work run the below command,


mvn clean test -Dtest=com.example.springsecurity.web.controllers.Video1SpringInmemoryUserdetailServiceControllerTest

In my next blog I will be introducing Jdbc implementation of authorization.

REFERENCE

Spring Security 3.1 by Robert Winch and Peter Mularien

Spring Security Certificate Authentication Authorization Example

For introduction to Spring Security refer this blog.

In continuation of my earlier blog Container based Security and Spring Security, in this blog, I will demonstrate how you can achieve Certificates Authentication and Authorization in Spring Security. As with all my blogs, the sample code for this is @ Github.

As mentioned in Enabling CLIENT-CERT based authorization on Tomcat,

  • You need to create keystore information
  • You need to change the connector configuration in tomcat to work with SSL
  • We dont need to configure MemoryRealm, because we use Spring Security for authentication

Continue and do the below steps,

  • Go to spring-mvc-client3 folder in the sample codebase and run “mvn clean package -DskipTests” it will create a war file in target folder, copy the war file into tomcat webapps folder.
  • Go to spring-mvc-client4 and repeat the maven command and copy the war file into tomcat webapps folder.
  • Start the tomcat server by going to <tomcat installed folder>/bin/startup.bat
  • Go to spring-mvc-client3 folder and run “mvn test” and notice all the tests are successful

In the web.xml you need to put the following code,

<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.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>

To understand what is going open spring-mvc-client3/src/main/webapp/WEB-INF/applicationContext-security.xml, you will notice below configuration,

<!-- There is no security requirement to access the html resources like css, js etc and maybe loggedout.jsp page -->
<http pattern="/static/**" security="none"/>
<http pattern="/loggedout.jsp" security="none"/>

<http use-expressions="true">
<!-- Only supervisor can access secure1 webresources and all the resources under it and this resource can be accessed only if the request is https-->
<intercept-url pattern="/secure1/**" access="hasRole('supervisor')" requires-channel="https"/>
<!-- You have to be logged in to access secure folder and all resources under it -->
<intercept-url pattern="/secure/**" access="isAuthenticated()" requires-channel="https"/>
<!-- You have to be logged in to access secure folder and all resources under it -->
<intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" requires-channel="https"/>

<!-- Here is where you provide a regular expression to extract user identity from the certificate and pass it to a authentication provider, in this example,
there is a dummy authentication provider as below, in real example, the auth provider is something like LDAP -->
<x509 subject-principal-regex="CN=(.*?)," user-service-ref="accountService" />
</http>

<authentication-manager>
<authentication-provider>
<!-- Dummy anthentication provider -->
<user-service id="accountService">
<user name="client1" password="" authorities="supervisor" />
<user name="client2" password="" authorities="user" />
</user-service>
</authentication-provider>
</authentication-manager>

Open the JUnit test @ spring-mvc-client3/src/test/java/com/goSmarter/springsecurity/SecureHttpClient1Test.java and see based on the above configuration, I have 2 positive testcases and 1 negative testcase. If you notice testSecurePage, user “client1” can access “secure1” folder because he is a “supervisor”, it is returning http OK(200). If you notice testSecurePageNegativeCase, user “client2” cannot access “secure1” folder because he is a “user”, it is giving forbidden(403) http code.

I hope this blog helped you.

Enabling CLIENT-CERT based authorization on Tomcat – Part 2

In continuation of my earlier blogs Enabling CLIENT-CERT based authorization on Tomcat and Enabling SSL in Tomcat, in this blog I will demonstrate, how you can configure multiple application to control access to their web resources using CLIENT-CERT mechanism. Please read both the above blogs, before reading further.

There are 2 tomcat web applications in the code base in GitHub called “client1” and “client2”, if you go to web.xml of client1 it looks as below,

<security-constraint>
<web-resource-collection>
<web-resource-name>Demo App</web-resource-name>
<url-pattern>/secure/*</url-pattern>
<http-method>GET</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>secureconn</role-name>
</auth-constraint>
</security-constraint>

<login-config>
<auth-method>CLIENT-CERT</auth-method>
<realm-name>Demo App</realm-name>
</login-config>

<security-role>
<role-name>secureconn</role-name>
</security-role>

If you notice, there is a web resource called “/secure” it will be only accessed by a user with role “secureconn”. And in “client2” web.xml you have,

<security-constraint>
<web-resource-collection>
<web-resource-name>Demo App</web-resource-name>
<url-pattern>/secure/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>secureconn1</role-name>
</auth-constraint>
</security-constraint>

Again, if you notice in client2, there is a web resource called “/secure” it will be only accessed by a user with role “secureconn1”.

In a typical enterprise, you will use a LDAPRealm and users with secureconn role can access client1 web resource and users with secureconn1 role can access client2 web resource. But in this demo we will use MemoryRealm and configure tomcat-users.xml with these users and roles as below,

<role rolename="secureconn"/>
<user username="CN=client1, OU=Application Development, O=GoSmarter, L=Bangalore, ST=KA, C=IN" password="null"  roles="secureconn"/>
<role rolename="secureconn1"/>
<user username="CN=client2, OU=Application Development, O=GoSmarter, L=Bangalore, ST=KA, C=IN" password="null"  roles="secureconn1"/>

I hope this blog helped you.