Test your knowledge!Take a quiz to access yourself.

Apache Shiro – Quickly getting it up for Java Application

The Java geeks might be waiting for this post and many fans who commented on our last post about Shiro – Apache Shiro – Features and Terminologies would be very happy to see this. But before taking you into this, i will suggest  you to sharpen your java understanding and be ready for things which might twist your brain muscles. We might quickly come up with certain terminologies which is related to Shiro or Java’s basics, so just stay focused.

So I wont go into Shiro again. What is Shiro? What it can do? blah blah… Just read above mentioned post for that. Also If you are still getting ready for Java, then this is not your place. Learn java well before reading this.

Let’s get started. First off all get the latest JDK with you and download Shiro’s binaries or add through maven  from its download page (assuming you know maven otherwise read about it from our blog). We will follow maven build as it takes care of dependencies. Add following maven dependency in pom.xml.

<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.2.3</version>
</dependency>

Now add shiro.ini into your project’s classpath. Shiro.ini is the file which all variables which are required to initialize Shiro framework are present. We will go into details later. Let’s first create project and run it.

#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
#
# =============================================================================
# Quickstart INI Realm configuration
#
# For those that might not understand the references in this file, the
# definitions are all based on the classic Mel Brooks' film "Spaceballs". ;)
# =============================================================================

# -----------------------------------------------------------------------------
# Users and their assigned roles
#
# Each line conforms to the format defined in the
# org.apache.shiro.realm.text.TextConfigurationRealm#setUserDefinitions JavaDoc
# -----------------------------------------------------------------------------
[users]
# user 'root' with password 'secret' and the 'admin' role
root = secret, admin
# user 'guest' with the password 'guest' and the 'guest' role
guest = guest, guest
# user 'presidentskroob' with password '12345' ("That's the same combination on
# my luggage!!!" ;)), and role 'president'
presidentskroob = 12345, president
# user 'darkhelmet' with password 'ludicrousspeed' and roles 'darklord' and 'schwartz'
darkhelmet = ludicrousspeed, darklord, schwartz
# user 'lonestarr' with password 'vespa' and roles 'goodguy' and 'schwartz'
lonestarr = vespa, goodguy, schwartz

# -----------------------------------------------------------------------------
# Roles with assigned permissions
# 
# Each line conforms to the format defined in the
# org.apache.shiro.realm.text.TextConfigurationRealm#setRoleDefinitions JavaDoc
# -----------------------------------------------------------------------------
[roles]
# 'admin' role has all permissions, indicated by the wildcard '*'
admin = *
# The 'schwartz' role can do anything (*) with any lightsaber:
schwartz = lightsaber:*
# The 'goodguy' role is allowed to 'drive' (action) the winnebago (type) with
# license plate 'eagle5' (instance specific id)
goodguy = winnebago:drive:eagle5

Now you have to create a main method class file and add following code into it. In our case we created TestShiro.java.

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;


public class TestShiro {
    
    public static void main(String[] args) {

        // The easiest way to create a Shiro SecurityManager with configured
        // realms, users, roles and permissions is to use the simple INI config.
        // We'll do that by using a factory that can ingest a .ini file and
        // return a SecurityManager instance:

        // Use the shiro.ini file at the root of the classpath
        // (file: and url: prefixes load from files and urls respectively):
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        SecurityManager securityManager = factory.getInstance();

        // for this simple example quickstart, make the SecurityManager
        // accessible as a JVM singleton.  Most applications wouldn't do this
        // and instead rely on their container configuration or web.xml for
        // webapps.  That is outside the scope of this simple quickstart, so
        // we'll just do the bare minimum so you can continue to get a feel
        // for things.
        SecurityUtils.setSecurityManager(securityManager);

        // Now that a simple Shiro environment is set up, let's see what you can do:

        // get the currently executing user:
        Subject currentUser = SecurityUtils.getSubject();

        // Do some stuff with a Session (no need for a web or EJB container!!!)
        Session session = currentUser.getSession();
        session.setAttribute("someKey", "aValue");
        String value = (String) session.getAttribute("someKey");
        if (value.equals("aValue")) {
            System.out.println("Retrieved the correct value! [" + value + "]");
        }

        // let's login the current user so we can check against roles and permissions:
        if (!currentUser.isAuthenticated()) {
            UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
            token.setRememberMe(true);
            try {
                currentUser.login(token);
            } catch (UnknownAccountException uae) {
                System.out.println("There is no user with username of " + token.getPrincipal());
            } catch (IncorrectCredentialsException ice) {
                System.out.println("Password for account " + token.getPrincipal() + " was incorrect!");
            } catch (LockedAccountException lae) {
                System.out.println("The account for username " + token.getPrincipal() + " is locked.  " +
                        "Please contact your administrator to unlock it.");
            }
            // ... catch more exceptions here (maybe custom ones specific to your application?
            catch (AuthenticationException ae) {
                //unexpected condition?  error?
            }
        }

        //say who they are:
        //print their identifying principal (in this case, a username):
        System.out.println("User [" + currentUser.getPrincipal() + "] logged in successfully.");

        //test a role:
        if (currentUser.hasRole("schwartz")) {
            System.out.println("May the Schwartz be with you!");
        } else {
            System.out.println("Hello, mere mortal.");
        }

        //test a typed permission (not instance-level)
        if (currentUser.isPermitted("lightsaber:weild")) {
            System.out.println("You may use a lightsaber ring.  Use it wisely.");
        } else {
            System.out.println("Sorry, lightsaber rings are for schwartz masters only.");
        }

        //a (very powerful) Instance Level permission:
        if (currentUser.isPermitted("winnebago:drive:eagle5")) {
            System.out.println("You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'.  " +
                    "Here are the keys - have fun!");
        } else {
            System.out.println("Sorry, you aren't allowed to drive the 'eagle5' winnebago!");
        }

        //all done - log out!
        currentUser.logout();

        System.exit(0);
    }

}

Output when we run this code:

Retrieved the correct value! [aValue]
User [lonestarr] logged in successfully.
May the Schwartz be with you!
You may use a lightsaber ring.  Use it wisely.
You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'.  Here are the keys - have fun!

 

After seeing long set of code with lot of comments  you might have got an idea of its working. If in case you have not got it, you can continue reading for the drilled details of code. Also don’t be sleepy or in hurry, its just requires one read and then you will be ready for all kind of java projects.

Shiro.ini has two tags [users] and [roles] in it which divides the file into two parts and defines the related properties. There are other tags also but those are not related to this tutorial.

Users are defined in following fashion: username = password, role1, role2, role3….. for example:

lonestarr = vespa, goodguy, schwartz

Here lonestarr is username, vespa is password and goodguy and schwartz are roles of lonestarr.

Roles are defined in following fashion: rolename = permission1, permission2…. for example:

goodguy = winnebago:drive:eagle5

Here goodguy is rolename and winnebago:drive:eagle5 is a permission. You would have noticed permission string is seperated by colon (:) , and has multiple strings. Is this one permission, yes it is. But it is defined like this because using this you can control permission in various ways. Let’s look at permission in this way, that you want to give permission to a certain role for printing but to other role just getting stats of printer. You can write it in following fashion.

teacher = printer:print                //teacher role can print
cashier = printer:statistics           // cashier can collect statistics and order cartridges and papers
admin = printer:*                      // admin can do all kind of stuff

For now lets concentrate on understanding basics, for more deeper understanding read our upcoming tutorials.

Enough on the ini file, we will move to the java class file and jump into code. Don’t freak out if in case you don’t understand any term, just google it out.

Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);

These 3 lines are required to invoke shiro’s environment for your application. Simply understanding it, the first line gets the shiro.ini properties and creates a factory object, then the second line takes out security manager from the factory instance and the third line sets the security manager in security utils and made it available application wise.

Now we just have to get current subject of the application:

Subject currentUser = SecurityUtils.getSubject();

An now we can do any operation for the current user. If user is not logged in, let him login, if he is already logged in check his role and given permissions to him and let him do certain operations.

 if (!currentUser.isAuthenticated()) {
 UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
 token.setRememberMe(true);
 try {
 currentUser.login(token);
 } catch (UnknownAccountException uae) {
 System.out.println("There is no user with username of " + token.getPrincipal());
 } catch (IncorrectCredentialsException ice) {
 System.out.println("Password for account " + token.getPrincipal() + " was incorrect!");
 } catch (LockedAccountException lae) {
 System.out.println("The account for username " + token.getPrincipal() + " is locked. " +
 "Please contact your administrator to unlock it.");
 }
 // ... catch more exceptions here (maybe custom ones specific to your application?
 catch (AuthenticationException ae) {
 //unexpected condition? error?
 }
 }

Here we are checking if user is not logged in, let him login. We are creating a token using his username and password and sending it to realm for authentiation. If authenticated then we can move further otherwise it will through exceptions, as we have catched in the code.

if (currentUser.hasRole("schwartz")) {
 System.out.println("May the Schwartz be with you!");
 } else {
 System.out.println("Hello, mere mortal.");
 }
//test a typed permission (not instance-level)
 if (currentUser.isPermitted("lightsaber:weild")) {
 System.out.println("You may use a lightsaber ring. Use it wisely.");
 } else {
 System.out.println("Sorry, lightsaber rings are for schwartz masters only.");
 }

Now we got user into our system, we can check for his role or permissions and do a certain action or print message for that.

You might have noticed it is very easy to handle shiro through ini file and code, you just have to be smart and understand it. Yeah you can understand a machine too 😉 . So that’s it for now… Its a long tutorial but it would have given an idea how to use shiro in just 5 mins in your java app. Next time I will show you a classic case of Java webapp secured using shiro. Just keep visiting and don’t forget to comment your thoughts below 🙂 .

 

2 Comments

Add a Comment

Your email address will not be published. Required fields are marked *