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 of the following components:
- Java 1.6 JDK
- Grails (used to run these Web application samples)
Common abbreviations
- API: application Programming Interface
- HTTP: Hypertext Transfer Protocol
- JAR: Java Archive File
- JDBC: Java Database Connection
- JDK: Java Development Toolkit
- LDAP: Lightweight Directory Access Protocol
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.
Back to top of page
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.
Overall authentication solution from IBM
White paper "Enhancing identity assurance across all access Scenarios cost effectively with IBM ISS identity and Access Management Services "explores a fully integrated, enterprise-wide, cost-effective authentication solution across a wide range of business applications and access scenarios.
This solution provides a highly secure, centralized authentication infrastructure that can be easily integrated with a variety of applications or IT infrastructure components through its APIs or standard authentication protocols such as RADIUS or LDAP. It supports a wide range of hardware and software or phone-based authentication tokens, providing maximum flexibility in selecting specific authentication methods.
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 Shiro Session
object allows a user session to be used without the need 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 organisation= "Com.nathanagood.examples" module= "Shirotest"/> <configurations> <conf name= "Dist" des cription= "Dependency configuration for distribution."/> </configurations> <dependencies> < Dependency org= "commons-logging" name= "commons-logging" rev= "1.1.1" conf= "Dist->default"/> <de Pendency org= "org.slf4j" name= "Slf4j-log4j12" rev= "1.5.8" conf= "Dist->default"/> <dependency o Rg= "Org.apache.shiro" name= "Shiro-core" rev= "1.0.0-incubating" conf= "Dist->default"/> <depende ncy org= "Org.apache.shiro" name= "Shiro-web" rev= "1.0.0-incubating" conf= "Dist->default"/> </depend Encies></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.PA Th "> <fileset dir=" ${basedir}/ivy-lib "> <include name=" **/*.jar "/> </FILESET&G T </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 patte Rn= "${project.lib}/[conf]/[artifact". [ext] "sync=" true "/> </target> <target name=" Usage "> <echo message=" Use--projecthelp to L Earn 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 a 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 = Factory. 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.
SecurityUtils
An object is a singleton, which means that different objects can use it to gain access to the current user. Once this has been successfully set SecurityManager
, it can be called in different parts SecurityUtils.getSubject()
of the application to get the current user's information.
Back to top of page
User Tokens
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 the user UsernamePasswordToken
name and password used to specify the user.
UsernamePasswordToken
class implements an AuthenticationToken
interface that provides a way to obtain the credentials and the user's principal (account identity). UsernamePasswordToken
applies to most applications, and you can also extend the interface when needed AuthenticationToken
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 top of page
Simple Authentication
At this point, this simple example covers: Start Shiro SecurityManager
, get the current user, and record the user's unauthenticated. The next example will use UsernamePasswordToken
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 object described in the previous section UsernamePasswordToken
, as shown in Listing 4.
Listing 4. Using the Usernamepasswordtoken class
//snipped ... same as Before.public class Shirotest {private static Logger Logger = Loggerfac Tory.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.getinstance ( ); 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 ()); }}
UsernamePasswordToken
Objects are instantiated by a combination of user names and passwords. The token is then passed to Subject
the method of the class login()
.
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. login()
method will now throw one 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 one 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 top of page
Authenticating with LDAP
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 an ActiveDirectoryRealm
object that allows user authentication for LDAP. This example uses an object configured within the INI file ActiveDirectoryRealm
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 Inisecuritymanagerfactory, 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.getinstan CE (); Securityutils.setsecuritymanager (SecurityManager); Subject user = Securityutils.getsubject (); Logger.info ("User is authenticated:" + user.isauthenticated ()); Usernamepasswordtoken token = new Usernamepasswordtoken ("Cn=cornelius buckley,ou=people,o=sevenseas", "Argh"); User.login (token); Logger.info ("User is authenticated:" + user.isauthenticated ()); }}
In addition to the INI file name and user name and password, the code is the same as the code that was previously authenticated with the records in INI files. This similarity occurs because you can use the INI file to configure the Shiro. The INI records used to set Shiro authentication for Apache Directory are shown in Listing 6.
Listing 6. Actived.ini file
[Main]activedirectoryrealm = Org.apache.shiro.realm.activedirectory.ActiveDirectoryRealmactiveDirectoryRealm.systemUsername = uid=admin,ou= Systemactivedirectoryrealm.systempassword = Secretactivedirectoryrealm.searchbase = o=sevenSeas,ou= Peopleactivedirectoryrealm.url = ldap://localhost:10389
Note: I use Apache Directory Studio to change the user's password to a value that can be put into the test code to make sure it works.
Back to top of page
Run a Grails Web application
There are two basic techniques you can use to apply Shiro to a Web application. First, you can use this API to incorporate the code shown here into a basic servlet. Second, you can use the HTTP filter that comes with Shiro. This example shows the second trick, because using filters takes advantage of the built-in Web application server technology and the pre-written code from the Shiro project.
This example shows how to use these filters within Grails. Grails is a project designed to allow you to write Groovy Web applications as quickly as possible by using a formula-first principle (convention-over-configuration). For more information about Grails, see resources.
For Shiro filters, you will typically add the required filter entries to the Web. xml file manually. However, Grails generates the Web. xml file every time you start the application, so you do not have to manually modify Web. Xml.
Fortunately, Grails provides plug-ins that can be integrated into the Web. XML build process and allow you to also participate in writing these items within the Web. xml file. Today, Grails has a lot of available plugins, including this plugin for Shiro. It is recommended to try this Shiro Grails plugin, which provides several new scripts to run these scripts to create different domains and controllers.
Or, if you prefer to add these items yourself and configure them, you can also write your own plug-in. For Grails, it's easy to write a new plugin. To create a Grails plugin that adds the required Shiro filter entries to the Web. xml file, you can use the following command:
> Grails create-plugin shirowebxml
Once you have created this plug-in project, edit the Shirowebxmlplugin.groovy file and add the code shown in Listing 7.
Listing 7. Sample Plug-in
Class Shirowebxmlplugin { //snipped plugin details ... def dowithwebdescriptor = {XML --def filterelement = XML. ' Filter ' def lastfilter = Filterelement[filterelement.size ()-1] Lastfilter + { ' filter ' { ' Filter-name ' ("Shirofilter") ' Filter-class ' ("Org.apache.shiro.web.servlet.IniShiroFilter") ' Init-param ' { ' param-name ' ("config") ' Param-value ' ("\n#config")}}} def filtermappingelement = XML. ' Filter-mapping ' def lastfiltermappingelement = filtermappingelement[filtermappingelement.size ()-1] lastfiltermappingelement + { ' filter-mapping ' { ' filter-name ' ("Shirofilter") ' Url-pattern ' (" /*") } } }}
This code runs when Grails executes the Web. xml file.
Before starting this plug-in application test it, copy the Shiro JAR file downloaded with Ivy to the Lib folder of this plugin. After you have the JAR file, use the following command to test whether the plugin works:
Grails Run-app
If the plug-in application starts successfully, you can package it for use in one of the sample projects. To package this plugin, use the following command:
Grails Package-plugin
You can install this new with the following command ShiroWebXmlPlugin
:
CD Myappgrails Install-plugin/path/to/shiro-web-xml-1.0.zip
Back to top of page
Trouble shooting
If it UnavailableSecurityManagerException
does, it may SecurityManager
not be set correctly. getSubject()
Make sure it is set on the object before calling the method SecurityUtils
.
Connecting to an LDAP server can be a bit difficult. If you get one javax.naming.CommunicationException
, check the host name and port of this LDAP server. Even if you are not using Apache Directory,apache Directory Studio (which can be installed separately), it can also help you troubleshoot connection failures and name problems.
If you do not initialize your environment with an Ant Ivy script, you may get a missing class error. Even without the Apache Commons Logging Library ( commons-logging
), this INI file sample can still run, but running this LDAP example causes an exception. At this point, you can use apace Commons BeanUtils
to parse the INI file and set the value on the object.
Back to top of page
Conclusion
Shiro is a framework within Apache incubator that allows you to add authentication and authorization to your application. It supports different ways of authenticating storage, such as LDAP, Kerberos, and AD DS. Shiro's minimal dependency, coupled with its relatively simple configuration, makes it a good choice for an in-app security framework.
Transfer from: http://www.ibm.com/developerworks/cn/web/wa-apacheshiro/#icomments
About Apache Shiro