Apache Shiro™ is a powerful and easy-to-use Java security framework that performs authentication, authorization, encryption, and session management. With Shiro’s easy-to-understand APIS, you can quickly and easily secure any application – from the smallest mobile applications to the largest Web and enterprise applications.

1. Apache Shiro four Cornerstones

Shiro provides security apis for the platform’s applications through the following.

  • Authentication: Indicates the identity Authentication.
  • Authorization: Authorization.
  • Crpytography: To protect or hide data that could be snowed on.
  • Session Management: Session Management

Shiro provides ancillary features such as Web application security, unit testing, and multithreading support, but they are all built around these four cornerstones.

1.1 the Authentication

Authentication is the process of verifying a user’s identity. That is, when users authenticate with the application, they prove that they are, in fact, who they say they are. This is sometimes called “logging in.” This is usually a three-step process.

  1. Collect user identity information, calledThe main bodyAnd support proof of identity, calledcredentials.
  2. Submit the principal and credentials to the system.
  3. If the submitted credentials match the system’s expectations for the user identity (principal), the user is considered authenticated. If they do not match, the user is not considered authenticated.

A common example of this process that everyone is familiar with is the username/password combination. When most users log in to a software application, they typically provide a username (principal) and a supporting password (credentials). Passwords stored in the system (or their representation) are considered authenticated if they match the password specified by the user.

Shiro supports the same workflow in a simple and intuitive way. As we said, Shiro has a topic-centric API – almost everything you do with Shiro at run time is done by interacting with the Subject currently being executed. Therefore, to log in to a topic, you simply call its login method, passing an AuthenticationToken instance that represents the submitted principal and credentials (in this case, the username and password).

//1. Acquire submitted principals and credentials:
AuthenticationToken token = new UsernamePasswordToken(username, password);

//2. Get the current Subject:
Subject currentUser = SecurityUtils.getSubject();

//3. Login:
currentUser.login(token);
Copy the code

Shiro’s API easily mirrors common workflows. You will continue to treat this simplicity as a topic for all topic operations. When the login method is called, the SecurityManager receives the AuthenticationToken and dispatts it to one or more configured domains, allowing each domain to perform authentication checks as needed. Each Realm can react to submitted AuthenticationTokens as needed. But what happens if a login attempt fails? What if the user specified the wrong password? You can handle the failure by reacting to Shiro’s runtime AuthenticationException.

//3. Login:
try {
    currentUser.login(token);
} catch(IncorrectCredentialsException ice) {... }catch(LockedAccountException lae) {... }...catchAuthenticationException (ae) {... }Copy the code

You can choose to capture one of the AuthenticationException subclasses and react concretely, or generally handle any AuthenticationException (for example, show the user a generic “Incorrect username or password” message). You can choose based on application requirements.

After successfully logging in to a topic, they are considered authenticated, and you generally allow them to use your application. But just because users prove their identity doesn’t mean they can do whatever they want in your application. This leads to the next question, “How do I control what users are allowed to do?” Deciding what users are allowed to do is called authorization. We show you how Shiro enables authorization.

1.2 Authorization

Authorization is essentially access control – controlling what users can access within an application, such as resources, web pages, etc. Most users perform access control by using concepts such as roles and permissions. That is, users are generally allowed to do or not do something based on the roles and/or permissions assigned to them. Your application can then control exposed functionality based on checks for these roles and permissions. As you might expect, the Subject API allows you to perform role and permission checks very easily. For example, the code snippet in Listing 7 shows how to check if a Subject has been assigned a role.

if(subject. HasRole (" administrator ")) {//show the ‘Create User’ button
} else {
    //grey-out the button?
} 
Copy the code

Permission checking is another way to perform authorization. Examining roles as shown in the example above leads to one major drawback: you cannot add or remove roles at run time. The code is hardcoded using the role name, so if you change the role name and/or configuration, your code will be broken! If you want to be able to change the meaning of roles at run time, or add or remove roles as needed, you must rely on something else.

if(the subject isPermitted (" user: create ")) {//show the ‘Create User’ button
} else {
    //grey-out the button?
} 
Copy the code

By having permissions that reflect the original functionality of the application, you only need to change the permissions to change the functionality of the application. In turn, you can assign permissions to roles or users as needed at run time.

This allows any role or user assigned “User: Create” privileges to click the “Create User” button, and these roles and assignments can even be changed at run time, providing a very flexible security model.

The “User: Create” string is an example of a permission string that follows some parsing convention. Shiro supports this convention out of the box through WildcardPermission. WildcardPermission is very flexible when creating security policies and even supports things like instance-level access control.

if(the subject isPermitted (" user: delete: jsmith ")) {/ / delete the 'jsmith' user
} else {
    / / don 't delete' jsmith '
}
Copy the code

1.3 Session Management

Apache Shiro offers something unique in the security framework space:

A consistent session API that can be used for any application and any architectural layer. That is, Shiro enables the session programming paradigm for any application – from small daemon standalone applications to the largest clustered Web applications. This means that application developers who want to use sessions no longer need to use servlets or EJB containers that would otherwise be unnecessary.

But perhaps one of the most important benefits of Shiro sessions is that they are container independent. This has subtle but extremely powerful implications. For example,

  1. Let’s consider session clustering. How many container-specific ways are there to cluster sessions for fault tolerance and failover? Tomcat does things differently than Jetty, as opposed to, say, Websphere. But with Shiro sessions, you can get a container-independent clustering solution. Shiro’s architecture allows pluggable Session data stores, such as enterprise caches, relational databases, NoSQL systems, and more. This means that you can configure session clustering once and it will work the same way regardless of your deployment environment (Tomcat, Jetty, JEE Server, or standalone applications). 2. Another benefit of Shiro sessions is that session data can be shared across client technologies if needed. For example, Swing desktop clients can participate in the same Web application session if desired – useful if the end user uses both. So how do you access a topic session in any environment? There are two theme methods, as shown in the following example:
Session Session = subject.getSession (); Session Session = subject.getSession (booleanThe create);Copy the code

These methods are conceptually the same as the HttpServletRequest API. The first method returns the Subject’s existing Session, or if it doesn’t already have one, it creates a new one and returns it. The second method takes a Boolean parameter that determines whether a new Session will be created (if it doesn’t already exist). Once you get the topic session, you can almost use it the same as HttpSession. Shiro’s team felt that the HttpSession API was most comfortable for Java developers, so we retained a lot of feeling. The big difference, of course, is that you can use Shiro Sessions in any application, not just Web applications.

Session session = subject.getSession(); The session. The getAttribute (" key "someValue); Date start = session.getStartTimestamp(); Date timestamp = session.getLastAccessTime(); session.setTimeout(millis); .Copy the code

1.4 Cryptography

Encryption is used to obfuscate or hide data, so third parties cannot pry into the data. Shiro’s encryption uses JDK related encryption.

Cryptography involves:

  • Hashes encryption
  • Password encryption

1.4.1 hash

In the JDK MessageDigest

try {
    MessageDigest md = MessageDigest.getInstance("MD5");
    md.digest(bytes);
    byte[] hashed = md.digest();
} catch (NoSuchAlgorithmException e) {
    e.printStackTrace();
} 
Copy the code

Shiro’s hash

String encodedPassword = newSha512Hash (password, salt, count).tobase64 ();Copy the code

The Shiro example is simpler than the JDK’s Cipher API:

  • You can instantiate CipherService directly – there are no strange or confusing factory methods.
  • Password configuration options are represented as Javabeans-compatible getters and setters – no weird and unintelligible “conversion strings.”
  • Encryption and decryption are performed in a single method call.
  • There is no mandatory check exception. You can grab Shiro’s CryptoException if you want

Shiro’s CipherService API has other benefits, such as the ability to support byte array-based encryption/decryption (called “block” operations) and stream-based encryption/decryption (for example, to encrypt audio or video).

Java cryptography does not need to be painful. Shiro’s encryption support is designed to simplify your job of securing your data.

2. Three main concepts of Apache Shiro

Shiro’s architecture has three main concepts – Subject, SecurityManager, and Realms.

2. 1 Subject

The word Subject is a security term that basically means “currently executing users.” But it’s not called “user,” because the word “user” is usually associated with humans. In the security world, the term “subject” can refer to a person, but it could also be a process, a daemon account, or anything like that. It simply means “what is currently interacting with the software.” However, for most intents and purposes, we can think of it as Shiro’s “user” concept. You can easily retrieve Shiro Subject anywhere in the code, as shown below.

import org.apache.shiro.subject.Subject; 
importorg.apache.shiro.SecurityUtils; . Subject currentUser = securityutils.getSubject ();Copy the code

Once a Subject is acquired, you can immediately access information about 90% of all the actions that the current user wants to perform with Shiro, such as login, logout, accessing its session, performing authorization checks, and so on. But more on that later. The key point here is that Shiro’s API is largely intuitive because it reflects the natural tendency of developers to think in ‘per-user’ security controls. It is also easy to access topics from anywhere in the code, allowing security operations to take place wherever needed.

2.2 the SecurityManager

The Subject is managed by the SecurityManager. Subject represents the mode of operation of the current user, and SecurityManager manages security operations for all users. The SecurityManager is the heart of Shiro and acts as a kind of “umbrella” object that references a number of internally nested security components that form an object graph.

Every application almost always has one instance of SecurityManager. It is essentially an application singleton (although it does not need to be static). As with almost everything in Shiro, the default SecurityManager implementation is POJO and can be configured using any POJO-compliant configuration mechanism – plain Java code, Spring XML, YAML,.properties,.ini files, etc. Basically anything that can be instantiated can use classes and call Javabeans-compatible methods.

2.2.1 Configuring Shiro using INI

[main] cm = org.apache.shiro.authc.credential.HashedCredentialsMatcher cm.hashAlgorithm = SHA-512 cm.hashIterations = 1024 # Base64 encoding (less text) :  cm.storedCredentialsHexEncoded = false iniRealm.credentialsMatcher = $cm [users] jdoe = TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJpcyByZWFzb2 asmith = IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbXNoZWQsIG5vdCBCopy the code

From the above configuration, we can see that there are two key configuration items when configuring Shiro using INI: [main] and [users]

The [main] section is used to configure the SecurityManager object and/or any objects used by the SecurityManager (such as Realms). In this example, we see that two objects are being configured:

  • Cm object, which is an instance of Shiro’s HashedCredentialsMatcher class. As you can see, the various properties of cm instance is through ‘nested points’ grammar (shown in listing 3 IniSecurityManagerFactory use agreement) to configure, to indicate the object map navigation and attribute set.
  • The iniRealm object, which is the component of SecurityManager used to represent user accounts defined in INI format.

Specify a static list of user accounts in the [Users] section – convenient for simple applications or testing.

2.2.2 Loading INI Configuration

/ / 1. Loading INI Configuration
Factory <SecurityManager> factory =
newIniSecurityManagerFactory (" classpath: shiro ini ");/ / 2. Create a SecurityManagerSecurityManager SecurityManager = factory.getInstance ();/ / 3. Make it accessibleThe SecurityUtils. SetSecurityManager (securityManager);Copy the code

3. Realms

Realms acts as Shiro’s “bridge” or “connector” to the application, meaning that Shiro looks for many of these things from one or more of the domains configured for the application when actually interacting with security-related data (such as user accounts) to perform authentication (login) and authorization (access control).

Realm is essentially a security-specific DAO: It encapsulates the connection details of the data source and makes the relevant data available to Shiro as needed. When configuring Shiro, you must specify at least one Realm for authentication and/or authorization. Multiple realms can be configured, but at least one is required.

Shiro provides Realms out of the box, connecting to many secure data sources (also known as directories) such as LDAP, relational databases (JDBC), text configuration sources (such as INI and properties files). If the default domain does not meet your needs, you can insert your own Realm implementation to represent a custom data source.

[main]
ldapRealm = org.apache.shiro.realm.ldap.JndiLdapRealm
ldapRealm.userDnTemplate = uid={0},ou=users,dc=mycompany,dc=com
ldapRealm.contextFactory.url = ldap://ldapHost:389
ldapRealm.contextFactory.authenticationMechanism = DIGEST-MD5
Copy the code

4. Web Support

By configuring network requests, restrictions, and so on, request interception, request filtering, and request to the corresponding resources.

Configuring network filtering:

<filter>
    <filter-name>ShiroFilter</filter-name>
    <filter-class>
        org.apache.shiro.web.servlet.IniShiroFilter
    </filter-class>
    <! -- no init-param means load the INI config from classpath:shiro.ini --> 
</filter>
<filter-mapping>
     <filter-name>ShiroFilter</filter-name>
     <url-pattern>/ *</url-pattern>
</filter-mapping>
Copy the code

This filter can read the previously mentioned shiro.ini configuration, so you can get a consistent configuration experience regardless of the deployment environment. Once configured, Shiro filters will filter each request and ensure that the request-specific topic is accessible during the request. And because it filters each request, you can perform security-specific logic to ensure that only requests that meet certain criteria are allowed.

4.1 URL-specific filter chains

Shiro supports security-specific filtering rules through its innovative URL filter linking feature. It allows you to specify a chain of Ad-hoc filters for any matching URL pattern. This means that you can use Shiro’s filtering mechanism to have a great deal of flexibility in executing security rules (or combinations of rules) – far more than you can define filters in web.xml alone.

[urls]
/assets/** = anon
/user/signup = anon
/user/** = user
/rpc/rest/** = perms[rpc:invoke], authc
/** = authc
Copy the code

The filter names seen above (Anon, User, Perms, AuthC) are special security-related filters provided by Shiro. These security filters can be mixed and matched to create a very customized security experience. You can also specify any other existing Servlet filters you might have.

4.2 Network Session Management

4.2.1 Default Http Session

For Web applications, Shiro defaults its session infrastructure to the existing Servlet container sessions we were used to. That is, when you call the methods subject-getSession () and subject-getSession (Boolean), Shiro will return the Session instance supported by the Servlet container’s HttpSession instance.

The advantage of this approach is that the business layer code calling subject-getSession () interacts with the Shiro Session instance – it has no “knowledge” that it is using the Web-based HttpSession object. This is a very good thing when it comes to maintaining clean separation across building floors.

4.2.2 Shiro’s local session in the Web layer

If you already have in your Web applications enabled Shiro’s native session management, because companies need Shiro sessions function (e.g., unrelated to the container cluster), of course. I hope it getSession () and the HttpSession API used with “native” session, Not a servlet container session.

It would be very frustrating if you had to refactor any code that uses the HttpServletRequest and HttpSession API to use Shiro’s Session API instead. Shiro certainly doesn’t expect you to. Instead, Shiro fully implements the Session portion of the Servlet specification to support native sessions in Web applications. This means that whenever a corresponding HttpServletRequest or HttpSession method call is invoked, Shiro delegates those calls to its internal local Session API.

5. Apache Shiro Framework Easter Eggs

There are other features in the Apache Shiro framework that are useful for securing Java applications, such as:

  • Maintain thread and concurrency support for topics across threads (Executor and ExecutorService support)
  • Callable and Runnable support the execution of logic as a specific topic
  • “Run as” support assumes the identity of another topic (useful in administrative applications, for example)
  • Test harness support, making it easy to fully test Shiro security code in both unit and integration tests