user authentication for Web applications using Apache Shiro
Shiro is an Apache incubator project designed to simplify authentication and authorization. In this article, learn about Apache Shiro and use an example to try to authenticate and authorize using Shiro in a Groovy Web application.
Apache Shiro is a framework that can be used for authentication and authorization. This article provides several examples to show how to use Shiro in a Java™ application and gives an overview of how to use it in a Grails Web application. To maximize the benefits from this article, you should be accustomed to creating Java applications and installing several components: Java 1.6 JDK Grails (used to run these Web application samples)
Authentication and Authorization
There are two security elements that are important when securing your system: Authentication and authorization. While these two terms represent different meanings, they are sometimes exchanged for their own role in application security.
Authentication refers to verifying the identity of a user. When verifying a user's identity, it is necessary to verify that the user's identity is indeed what they claim to be. In most applications, authentication is done through a combination of user names and passwords. As long as the user chooses a password that is difficult for others to guess, the combination of user name and password is often sufficient to establish identity. However, there are other authentication methods available, such as fingerprints, certificates, and build keys.
Once the authentication process has successfully established an identity, authorization is taken over for the purpose of restricting or permitting access. So, there is the possibility that the user can log on to a system through authentication, but is not authorized to do anything. Another possibility is that the user has some degree of authorization but is not authenticated.
When planning the security model for your application, you must handle these two elements to ensure that the system has sufficient security. Authentication is a common problem with applications (especially in the case of user and password combinations), so it's a good idea for the framework to handle this work. A reasonable framework provides the benefits of testing and maintenance, allowing you to focus on business issues rather than solving the problems that their solutions have already achieved.
Apache Shiro provides a security framework that can be used by various clients to apply this framework to their applications. The examples in this article are intended to introduce Shiro and highlight the basic tasks of authenticating users.
about Shiro
Shiro is a framework implemented in the Java language that provides authentication and authorization through an easy-to-use API. With Shiro, you can provide security for your application without having to write all of your code from scratch.
Because Shiro provides authentication with many different data sources, as well as Enterprise Session Management, it is ideal for single sign-on (SSO)-an ideal feature within a large enterprise, because within large enterprises, Users need to log in and use different systems frequently within a day. These data sources include JDBC, LDAP, Kerberos, and Microsoft®active directory®directory Services (AD DS).
The session object of Shiro allows a user session to be used without HttpSession. By using a common Session object, you can still use the same code even if the code is not running in a WEB application. There is no dependency on the application server or WEB Application Server session management, and you can even use Shiro in the command-line environment. In other words, code written with the Shiro API allows you to build a command-line application that connects to an LDAP server and is identical to the code used within the Web application to access the LDAP server. Download and install Shiro
Shiro is a pre-built binary release. You can download the Shiro JAR file or put the items into Apache Maven or Apache Ivy to get the files installed. This example uses Ivy to download the Shiro JAR file and other required libraries, and the script is simple, as shown in Listing 1. Listing 1. Apache Ivy file and Apache Ant script
<?xml version= "1.0" encoding= "UTF-8"?> <ivy-module version= "2.0" xmlns:xsi= "http://www.w3.org/2001/ Xmlschema-instance "xsi:nonamespaceschemalocation=" http://ant.apache.org/ivy/schemas/ivy.xsd "> <info organi sation= "Com.nathanagood.examples" module= "Shirotest"/> <configurations> <conf name= "Dist" Descrip tion= "Dependency configuration for distribution."/> </configurations> <dependencies> <d Ependency org= "commons-logging" name= "commons-logging" rev= "1.1.1" conf= "Dist->default"/> <d Ependency org= "org.slf4j" name= "Slf4j-log4j12" rev= "1.5.8" conf= "Dist->default"/> <dependenc Y org= "Org.apache.shiro" name= "Shiro-core" rev= "1.0.0-incubating" conf= "Dist->default"/> <de Pendency org= "Org.apache.shiro" name= "Shiro-web" rev= "1.0.0-incubating" conf= "Dist->default"/> < /dependencies> </IVY-MODULE>
<project name= "Shirotestapp" default= "Usage" basedir= "." xmlns:ivy= "Antlib:org.apache.ivy.ant" > <property name= "project.lib" value= "Lib"/> <path id= "Ivy.task. Path "> <fileset dir=" ${basedir}/ivy-lib "> <include name=" **/*.jar "/> </file
set> </path> <target name= "resolve" > <taskdef resource= "Org/apache/ivy/ant/antlib.xml" Uri= "Antlib:org.apache.ivy.ant" classpathref= "Ivy.task.path"/> <ivy:resolve/> < Ivy:retrieve pattern= "${project.lib}/[conf]/[artifact]. [ext] "sync=" true "/> </target> <target name=" Usage "> <echo message=" Use--projecthelp To learn more on this project "/> </target> </project>
For more information on using Ivy, see resources. If you do not use Maven or Ivy, you can download these Shiro JAR files from the download site provided in the Resources section of this article.
Once you have downloaded these libraries, simply add them to the CLASSPATH. Write the simple code shown in Listing 2, which obtains a reference to the current user and reports that the user is not authenticated. (Use the Subject class to represent this user.) ) Listing 2. Shirotest Java class
Package com.nathanagood.examples.shirotest;
Import Org.apache.shiro.SecurityUtils;
Import Org.apache.shiro.authc.UsernamePasswordToken;
Import Org.apache.shiro.config.IniSecurityManagerFactory;
Import Org.apache.shiro.subject.Subject;
Import Org.apache.shiro.util.Factory;
Import Org.slf4j.Logger;
Import Org.slf4j.LoggerFactory;
public class Shirotest {private static Logger Logger = Loggerfactory.getlogger (Shirotest.class);
public static void Main (string[] args) {//Using the inisecuritymanagerfactory, which'll use the ' an ' INI file
As the security file.
factory<org.apache.shiro.mgt.securitymanager> Factory = new Inisecuritymanagerfactory ("Auth.ini"); Setting up the SecurityManager ... org.apache.shiro.mgt.SecurityManager SecurityManager = FAC
Tory.getinstance ();
Securityutils.setsecuritymanager (SecurityManager);
Subject user = Securityutils.getsubject (); Logger.info ("UseR is authenticated: "+ user.isauthenticated ()); }
}
After you have added this code, create a file named Auth.ini. At this point, the file is blank; it only works to be able to run the example here to check if the code is working properly.
After creating the file, run the example. You should see an output containing an INFO login message that reports that the user is not logged in.
The Securityutils object is a singleton, which means that different objects can use it to gain access to the current user. Once you have successfully set up this SecurityManager, you can call Securityutils.getsubject () in different parts of the application to get the current user's information.
Back to page top user token
In Shiro terminology, a token refers to a key that can be used to log on to a system. The most basic and common token is usernamepasswordtoken, which specifies the user's user name and password.
The Usernamepasswordtoken class implements the Authenticationtoken interface, which provides a way to obtain the credentials and the user's principal (account identity). Usernamepasswordtoken is suitable for most applications, and you can also extend the Authenticationtoken interface when needed to include your own credentials. For example, you can extend this interface to provide the content of a critical file that your application uses to authenticate users.
Back to the top of the page simple authentication
At this point, this simple example covers the starting Shiro SecurityManager, obtaining the current user, and recording the user's unauthenticated credentials. The next example will use Usernamepasswordtoken and a user record stored in the INI file to show how to authenticate with the user name and password.
The Auth.ini file shown in Listing 3 now contains a user record, which contains the user name and password. You can define roles within this record and provide authorization for the application. Listing 3. auth.ini file
[Users]
Bjangles = Dance
Now, create the Usernamepasswordtoken object described in the previous section, as shown in Listing 4. Listing 4: Using the Usernamepasswordtoken class
Snipped. Same as before.
public class Shirotest {private static Logger Logger = Loggerfactory.getlogger (Shirotest.class);
public static void Main (string[] args) {//Using the inisecuritymanagerfactory, which'll use the ' an ' INI file
As the security file.
factory<org.apache.shiro.mgt.securitymanager> Factory = new Inisecuritymanagerfactory ("Auth.ini"); Setting up the SecurityManager ... org.apache.shiro.mgt.SecurityManager securitymanager = Factory.getinsta
NCE ();
Securityutils.setsecuritymanager (SecurityManager);
Subject user = Securityutils.getsubject ();
Logger.info ("User is authenticated:" + user.isauthenticated ());
Usernamepasswordtoken token = new Usernamepasswordtoken ("Bjangles", "Dance");
User.login (token);
Logger.info ("User is authenticated:" + user.isauthenticated ()); }
}
The Usernamepasswordtoken object is instantiated by a combination of user names and passwords. The token is then passed to the login () method of the Subject class.
Run the example again. Note that the logon message now reports that this user is authenticated.
To make sure that your code is working correctly and that you are not getting a false positive, change the password within the code or change the INI file and run the example again. The login () method now throws a incorrectcredentialsexception. This exception should be explicitly captured within the production code so that the application can respond appropriately when the user provides incorrect code.
If the user is not correct, the login () method throws a unknownaccountexception. We need to consider how to handle this exception, but we should not provide too much information to the user. A common practice is to not prompt the user for a valid user name, only the password is incorrect. This is because if someone tries to get access by guessing, then you never want to imply that the person he is guessing is the correct user name.
Back to the top of the page using LDAP for authentication
LDAP is a protocol used to query a directory on TCP/IP. These directories can hold any number of information about the user, including user IDs, contact information, group memberships, and so on. The LDAP directory is useful for the company's address book and is widely used.
AD DS is a common directory for user and group management, and it supports LDAP. Shiro does not contain a common LDAP security domain, but it contains a Activedirectoryrealm object that allows user authentication against LDAP. This example uses the Activedirectoryrealm object configured within the INI file to verify the identity of the user. Although AD DS differs from LDAP, this version of Shiro used in this article does not have a generic LDAP object.
It takes more work to have an LDAP server test this example than to write and run the sample itself. If you do not have access to an AD DS server, consider downloading and installing Apache Directory to provide a sample implementation of an LDAP server. Apache Directory is written in the Java language. Similarly, Apache Active Directory Studio is an Eclipse plug-in that can be used to browse LDAP data. It also has sample data that gives you a quick way to write code against known values without wondering whether the problem you are experiencing is a code problem or a data problem.
Listing 5 shows the code needed to authenticate a user stored in Apache Directory. Listing 5: Using LDAP for authentication
snipped. public class Shiroldaptest {private static Logger Logger = Loggerfactory.getlogger (shiroldaptest.class
); /** * @param args */public static void main (string[] args) {//Using the Inisecuritymanagerfactor
Y, which would use the-an INI file/as the security file.
factory<org.apache.shiro.mgt.securitymanager> Factory = new Inisecuritymanagerfactory ("Actived.ini"); Setting up the SecurityManager ... org.apache.shiro.mgt.SecurityManager securitymanager = Factory.getin
Stance ();
Securityutils.setsecuritymanager (SecurityManager);
Subject user = Securityutils.getsubject ();
Logger.info ("User is authenticated:" + user.isauthenticated ()); Usernamepasswordtoken token = new Usernam