Showing posts with label Provider. Show all posts
Showing posts with label Provider. Show all posts
, , , , , , , ,

Spring Security 3 - OpenID Login with myOpenID Provider

In this tutorial we'll add OpenID support for authenticating users in our existing Spring Security 3 application. It's required you understand how to setup a simple Spring Security application using a simple user-service. If you need a review, please read my other guide Spring MVC 3 - Security - Using Simple User-Service for an in-depth tutorial. We will use myOpenID as our OpenID provider. You are therefore required to setup an account with myOpenID.

We will based our application from the one we developed for Spring MVC 3 - Security - Using Simple User-Service tutorial. This is because everything is exactly the same. It's just a matter of configuration to enable OpenID support.

What is OpenID?
OpenID allows you to use an existing account to sign in to multiple websites, without needing to create new passwords.

You may choose to associate information with your OpenID that can be shared with the websites you visit, such as a name or email address. With OpenID, you control how much of that information is shared with the websites you visit.

With OpenID, your password is only given to your identity provider, and that provider then confirms your identity to the websites you visit. Other than your provider, no website ever sees your password, so you don’t need to worry about an unscrupulous or insecure website compromising your identity.

Source: http://openid.net/get-an-openid/what-is-openid/

What is myOpenID?
First and largest independent OpenID provider. Signing up with myOpenID gets you:
- Secure control of your digital identity
- Easy sign-in on enabled sites
- Account activity reports
- And a whole lot more!

Source: https://www.myopenid.com

Screenshot

Here's a screenshot of the application's OpenID login page:


Review

Enabling OpenID authentication is actually simple. Remember our application is based on the Spring MVC 3 - Security - Using Simple User-Service. Because of that all we need to do is modify the existing spring-security.xml config.

The Old Config

Here's our existing config file (for a thorough explanation please read the aforementioned guide):

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

<!-- This is where we configure Spring-Security -->
<security:http auto-config="true" use-expressions="true" access-denied-page="/krams/auth/denied" >

<security:intercept-url pattern="/krams/auth/login" access="permitAll"/>
<security:intercept-url pattern="/krams/main/admin" access="hasRole('ROLE_ADMIN')"/>
<security:intercept-url pattern="/krams/main/common" access="hasRole('ROLE_USER')"/>

<security:form-login
login-page="/krams/auth/login"
authentication-failure-url="/krams/auth/login?error=true"
default-target-url="/krams/main/common"/>

<security:logout
invalidate-session="true"
logout-success-url="/krams/auth/login"
logout-url="/krams/auth/logout"/>

</security:http>

<!-- Declare an authentication-manager to use a custom userDetailsService -->
<security:authentication-manager>
<security:authentication-provider user-service-ref="userDetailsService">
<security:password-encoder ref="passwordEncoder"/>
</security:authentication-provider>
</security:authentication-manager>

<!-- Use a Md5 encoder since the user's passwords are stored as Md5 in the database -->
<bean class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" id="passwordEncoder"/>

<!-- An in-memory list of users. No need to access an external database layer.
See Spring Security 3.1 Reference 5.2.1 In-Memory Authentication -->
<!-- john's password is admin, while jane;s password is user -->
<security:user-service id="userDetailsService">
<security:user name="john" password="21232f297a57a5a743894a0e4a801fc3" authorities="ROLE_USER, ROLE_ADMIN" />
<security:user name="jane" password="ee11cbb19052e40b07aac0ca060c23ee" authorities="ROLE_USER" />
</security:user-service>

</beans>
This configuration uses Spring Security's form-based login where you enter a username and password. At the end of the file, we have declared a list of users with corresponding credentials.

To authenticate a user, he must first provide a username and password which the application will compare in the in-memory list as declared in the user-service tag. If a match is found, the user is authenticated and authorized.

The New Config

Here's our new config file which enables OpenID support. Notice almost everything is still exactly the same!

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

<!-- This is where we configure Spring-Security -->
<security:http auto-config="true" use-expressions="true" access-denied-page="/krams/auth/denied" >

<security:intercept-url pattern="/krams/auth/login" access="permitAll"/>
<security:intercept-url pattern="/krams/main/admin" access="hasRole('ROLE_ADMIN')"/>
<security:intercept-url pattern="/krams/main/common" access="hasRole('ROLE_USER')"/>

<!-- Adding the openid-login tag activates Spring Security's support for OpenID -->
<security:openid-login
login-page="/krams/auth/login"
authentication-failure-url="/krams/auth/login?error=true"
default-target-url="/krams/main/common"/>

<security:logout
invalidate-session="true"
logout-success-url="/krams/auth/login"
logout-url="/krams/auth/logout"/>

</security:http>

<!-- Declare an authentication-manager to use a custom userDetailsService -->
<security:authentication-manager>
<security:authentication-provider user-service-ref="userDetailsService">
<security:password-encoder ref="passwordEncoder"/>
</security:authentication-provider>
</security:authentication-manager>

<!-- Use a Md5 encoder since the user's passwords are stored as Md5 in the database -->
<bean class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" id="passwordEncoder"/>

<!-- An in-memory list of users. No need to access an external database layer.
See Spring Security 3.1 Reference 5.2.1 In-Memory Authentication -->
<security:user-service id="userDetailsService">
<!-- user name is based on the returned open id identifier -->
<security:user name="http://krams915.myopenid.com/" password="" authorities="ROLE_USER, ROLE_ADMIN" />
</security:user-service>

</beans>

myOpenID: Enabling OpenID

With OpenID the same principle applies. To authenticate a user via myOpenID, he must perform the following steps:

1. Enter his OpenID login.


If we're using myOpenID, our OpenID login has the following format:
http://USERNAME.myopenid.com/
USERNAME is a placeholder for the user's chosen username during registration at myOpenID website. If for example we chose krams915 as our username, our OpenID login is:
http://krams915.myopenid.com/

2. Click the Login button.

The user is then forwarded to the myOpenID provider's login page. The user will be required to enter his password:

3. Login with the OpenID provider.

After a successful authentication, the provider will ask the user to continue and return back to the original application:

4. Spring Security will then perform two additional steps:
- Check if the returned OpenID identifier is registered in the application's database.
- Check if the returned OpenID identifier has authorities assigned in the application's database.

Notice these are the same steps used in a form-based login. This is the reason why it's beneficial that you understand how to setup a simple Spring Security 3 application using a simple user-details service first.

Authorities/Roles

Take note the job of the OpenID provider is to authenticate the user and returned back a valid OpenID identifier. The appropriate authorities or roles is the responsibility of the application. We must assign the roles in other words!
<security:user-service id="userDetailsService">
<!-- user name is based on the returned open id identifier -->
<security:user name="http://krams915.myopenid.com/" password="" authorities="ROLE_USER, ROLE_ADMIN" />
</security:user-service>
Notice for this username we assigned a ROLE_USER and ROLE_ADMIN.

Development

Let's enable OpenID authentication by modifying the config file. We just need to perform two steps:

1. Replace the form-login tag with openid-login tag
old config
<security:http auto-config="true" >
<security:form-login >
...omitted declarations
</security:http>

new config
<security:http auto-config="true" >
<security:openid-login >
...omitted declarations
</security:http>

2. Add a new user name inside the user-service tag
<security:user-service id="userDetailsService">
<security:user name="http://krams915.myopenid.com/" password="" authorities="ROLE_USER, ROLE_ADMIN" />
</security:user-service>
Notice the password attribute is empty. That's because the actual authentication is performed by the OpenID provider. The user name is based on the OpenID identifier returned by the provider. By default the OpenID login format is:
http://USERNAME.myopenid.com/
where USERNAME is a placeholder for the user's chosen username during registration at myOpenID website. However there are exceptions. Google and Yahoo do not follow this convention.

The JSP Login Page

Since we'll be using OpenID, we need to modify our JSP login page to use the OpenID form identifiers.

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

<h1>Login</h1>
<div id="login-error">${error}</div>

<c:url var="logoUrl" value="/resources/openidlogosmall.png" />
<p><img src="${logoUrl}"></img>Login with OpenID:</p>
<c:url var="openIDLoginUrl" value="/j_spring_openid_security_check" />
<form action="${openIDLoginUrl}" method="post" >
<label for="openid_identifier">OpenID Login</label>:
<input id="openid_identifier" name="openid_identifier" type="text"/>
<input type="submit" value="Login"/>
</form>

</body>
</html>
Notice there are two important identifiers:
j_spring_openid_security_checkthe virtual URL used by Spring Security to verify the user
openid_identifierthe input field for the user's OpenID login
These identifers are not arbirtrary! You must type them exactly as they are.

Determine the OpenID Identifier

The best way to determine the OpenID identifier is to set the application's logger to DEBUG level. Then run the application and check the logs. Of course, you need to have a working internet connection to be able to login with the provider. Our application uses log4j for logging.

Here's the log4j properties file:

log4j.properties
log4j.rootLogger=DEBUG,console

#Console Appender
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%5p] [%t %d{hh:mm:ss}] (%F:%M:%L) %m%n

#Custom assignments
log4j.logger.controller=DEBUG,console
log4j.logger.service=DEBUG,console

#Disable additivity
log4j.additivity.controller=false
log4j.additivity.service=false

Run the application and login with OpenID. After a successful authentication, check the logs. Here's a sample output:

log output
[DEBUG] [http-8080-Processor23 02:33:21] (Association.java:sign:261) Computing signature for input data:
assoc_handle:{HMAC-SHA256}{4d5629ae}{3l86JQ==}
claimed_id:http://krams915.myopenid.com/
identity:http://krams915.myopenid.com/
mode:id_res
ns:http://specs.openid.net/auth/2.0
op_endpoint:http://www.myopenid.com/server
response_nonce:2011-02-12T06:33:19ZVytTyL
return_to:http://localhost:8080/spring-security-openid-myopenid/j_spring_openid_security_check
signed:assoc_handle,claimed_id,identity,mode,ns,op_endpoint,response_nonce,return_to,signed

[DEBUG] [http-8080-Processor23 02:33:21] (Association.java:sign:267) Calculated signature: dD3h9VCvAZLWwUPW/Av+sdfjlKSSs+6bSKTsfsFWrA=
[DEBUG] [http-8080-Processor23 02:33:21] (ConsumerManager.java:verifySignature:1790) Local signature verification succeeded.
[ INFO] [http-8080-Processor23 02:33:21] (ConsumerManager.java:verifySignature:1850) Verification succeeded for: http://krams915.myopenid.com/
[DEBUG] [http-8080-Processor23 02:33:21] (ProviderManager.java:doAuthentication:127) Authentication attempt using org.springframework.security.openid.OpenIDAuthenticationProvider
Pay attention to these values:
claimed_id:http://krams915.myopenid.com/
identity:http://krams915.myopenid.com/
The claimed_id is what you need to add in the application's user-details table. In our case, it's an in-memory list.

If you really want to ensure that you're using the correct id, check the next line in the log file:
[ INFO] [http-8080-Processor23 02:33:21] (ConsumerManager.java:verifySignature:1850) Verification succeeded for: http://krams915.myopenid.com/
The value you see here is the id that must be placed in the user-details table. I'm adding emphasis here because if you're using other OpenID providers, you might get confused which id to used. This one is always correct.

Other OpenID Providers

For other OpenID providers, we'll discuss them in future tutorials since some of them may need special treatment like Google and Yahoo.

Below is a sample table that shows the different identifiers returned by various OpenID providers (We'll try to expand this list as we explore OpenID further in future tutorials):

MyOpenID http://krams915.myopenid.com/
Yahoo https://me.yahoo.com/a/ooXDFSsdfsqDbYAGuDSFSIK.PIuBsfdKA--#ade71
Google https://www.google.com/accounts/o8/id?id=BVlajJOIDjsldfjszSfjsM5sdfs0E
Blogspot http://krams915.blogspot.com/

Notice some OpenID providers adhere to the standard format, but others do not. To see other availabe OpenID providers, please visit http://openid.net/get-an-openid/

Run the Application

To run the application, use the following URL:
http://localhost:8080/spring-security-openid-myopenid/krams/auth/login
Of course, you will need to modify the username in the user-details service to match your provider's returned OpenID identifier. You will need to run the application first, authenticate, after a failed authentication, you should be able to see the claimed_id in the logs.

Conclusion

That's it. We've managed to enable OpenID support on our existing Spring Security 3 application by just modifying two simple configurations and a single JSP file. We've also discussed how to retrieve the OpenID identifier and how Spring Security evaluates this property.

The best way to learn further is to try the actual application.

Download the project
You can access the project site at Google's Project Hosting at http://code.google.com/p/spring-security-openid/

You can download the project as a Maven build. Look for the spring-security-openid-myopenid.zip in the Download sections.

You can run the project directly using an embedded server via Maven.
For Tomcat: mvn tomcat:run
For Jetty: mvn jetty:run

If you want to learn more about Spring MVC and integration with other technologies, feel free to read my other tutorials in the Tutorials section.
Continue reading Spring Security 3 - OpenID Login with myOpenID Provider
, , , , ,

Spring Security - MVC: Using an LDAP Authentication Provider

In this tutorial we will setup a simple Spring MVC 3 application, secured by Spring Security. Our users will be authenticated against an LDAP provider. We'll explore how we can configure an LDAP authentication provider. For this tutorial we will leveraged on our existing tutorials to lessen the repetition of steps. The overall structure of our application will be based on Spring Security 3 - MVC: Using a Simple User-Service Tutorial. This is a good exercise to show how easy we can change providers without disrupting the whole flow of our existing system. The LDAP server and entries will be based on LDAP - Apache Directory Studio: A Basic Tutorial

What is LDAP?
The Lightweight Directory Access Protocol (LDAP) is an application protocol for reading and editing directories over an IP network. A directory is an organized set of records. For example, the telephone directory is an alphabetical list of persons and organizations, with each record having an address and phone number. A directory information tree often follows political, geographic, or organizational boundaries. LDAP directories often use Domain Name System (DNS) names for the highest levels. Deeper inside the directory might appear entries for people, departments, teams, printers, and documents.

Source: http://en.wikipedia.org/wiki/LDAP
If this is your first time to LDAP, you might be wondering how is this different from an RDBMS. I suggest my readers to visit the following article Should I Use a Directory, a Database, or Both?

We'll start immediately with the spring-security.xml configuration.

spring-security.xml

Honestly, this is the only file that you need to change from the Spring Security 3 - MVC: Using a Simple User-Service Tutorial.

Actually, we just deleted a couple of entries. The old configuraiton contains an in-memory user-service provider:

The new configuration contains an LDAP authentication provider:

The real tricky part here is ensuring that you can connect to your LDAP server and ensuring that you've mapped correctly the attribute names from your ldap-authentication-provider to the LDAP Directory Information Tree.

To get a better understanding, let's examine the directory structure of the server. You will gain better insight if you've read first LDAP - Apache Directory Studio: A Basic Tutorial.

Here's server's structure:
mojo
|
|--groups
| |
| |--Admin
| |--User
|
|--users
|
|--guy1
|--guy2
|--guy3
|--guy4
Here's a screenshot of the server's directory:

Let's focus on the elements of the ldap-authentication-provider

The attribute value of the user-search-filter="(uid={0})" corresponds to the attribute we've declared for the users
The {0} in the (uid={0}) will be replaced by the username entered in the form.

The value of the user-search-base="ou=users" corresponds to the attribute we've declared in the directory tree

The attribute value of the group-search-filter="(uniqueMember={0})" corresponds to the attribute we've declared for the groups
The {0} in the (uniqueMember={0}) represents the Distinguished Name (DN) of the user. On our sample data, the dn for Hugo Williams is cn=Hugo Williams,ou=users,o=mojo. The DN is similar with the primary key in relational databases.

The value of the group-search-base="ou=groups" corresponds to the attribute we've declared in the directory tree

The attribute value of the group-role-attribute="cn" corresponds to the attribute we've declared for the groups. Spring Security uses this value of this attribute to determine the authorization level of the user.

The value of the role-prefix="ROLE_" is used to indicate what prefix should be added on the values received from group-role-attribute="cn". If you examine carefully the server's structure, we have two roles declared as cn=Admin and cn=User
The values that will be returned are Admin and User. With role-prefix="ROLE_", they will become ROLE_ADMIN and ROLE_USER respectively.

The LDAP Server
Let's examine ldap-server tag.


The url ldap://localhost:10389/o=mojo is composed of the server's url and port number ldap://localhost:10389/ and the base parent path o=mojo

The attribute manager-dn="uid=admin,ou=system" is based on the Distinguished Name of the admin. Normally, you will be provided by your administrator with a custom access, but for this tutorial we're relying on the default values to make things simple.

That's it. We've setup a simple Spring MVC 3 application, secured by Spring Security. Our users are authenticated against an LDAP provider. We've also explored how the various attributes map to an existing directory structure. This also means we can customize our mappings and assign different attribute names.

The best way to learn further is to try the actual application.

Download the project
You can access the project site at Google's Project Hosting at http://code.google.com/p/spring-security-ldap/

You can download the project as a Maven build. Look for the spring-security-ldap.zip in the Download sections.

You can run the project directly using an embedded server via Maven.
For Tomcat: mvn tomcat:run
For Jetty: mvn jetty:run
Continue reading Spring Security - MVC: Using an LDAP Authentication Provider