Exploring Apache Shiro
Join the DZone community and get the full member experience.
Join For FreeI was looking at some implementations for "RememberMe" or persistent session functionality and came across Apache Shiro. From the project website:
"Apache Shiro is a powerful and easy-to-use Java security framework that performs authentication, authorization, cryptography, and session management. With Shiro’s easy-to-understand API, you can quickly and easily secure any application – from the smallest mobile applications to the largest web and enterprise applications."
It was an interesting find. For the first time, I saw a session management implementation that is simple and works outside a web container. Indeed the APIs were simple enough to use in an application. While the documentation is reasonably good, I could not find an end-to-end sample with a configuration. So here is something I wrote to play with the APIs.
This code is implements a standalone Username and Password based authentication module. The dummy realm implementation simply returns an empty credential (User Info) pair. So if you plan to use database backed authentication, substitute the dummy implementation with say JDBC code or use JdbcRealm.
1. Create shiro.ini that will be used to initialize Shiro's SecurityManager.
[main] sessionManager = org.apache.shiro.session.mgt.DefaultSessionManager # ensure the securityManager uses our native SessionManager securityManager.sessionManager = $sessionManager #set the sessionManager to use an enterprise cache for backing storage: sessionDAO = org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO securityManager.sessionManager.sessionDAO = $sessionDAO cacheManager = org.apache.shiro.cache.ehcache.EhCacheManager securityManager.cacheManager = $cacheManager # Session validation sessionValidationScheduler = org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler # Session timeout securityManager.sessionManager.globalSessionTimeout = 3600000 # Default is 3,600,000 millis = 1 hour: sessionValidationScheduler.interval = 3600000 sessionValidationScheduler.sessionManager = $sessionManager # Auth myRealm = com.session.security.shiro.auth.CustomRealm myRealmCredentialsMatcher = org.apache.shiro.authc.credential.AllowAllCredentialsMatcher myRealm.credentialsMatcher = $myRealmCredentialsMatcher #Remember Me rememberMe = org.apache.shiro.web.mgt.CookieRememberMeManager securityManager.rememberMeManager = $rememberMe [users] [roles] [urls]
Note: We are using AllowAllCredentialsMatcher that always returns true while matching credentials. The configuration also uses EhCache for storing sessions. Also note that DefaultSessionManager does not have a default implementation for "RememberMe". Take a look at DefaultWebSecurityManager. It uses CookieRememberMeManager as a default implementation which is useful in a webapp.
2. Custom Realm
public class CustomRealm extends AuthenticatingRealm { private CredentialsMatcher credentialsMatcher; public String getName() { return "CustomRealm"; } public boolean supports(AuthenticationToken token) { return true; } public CredentialsMatcher getCredentialsMatcher() { return credentialsMatcher; } public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) { this.credentialsMatcher = credentialsMatcher; } @Override protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken token) throws AuthenticationException { return new SimpleAuthenticationInfo("", "".toCharArray(), getName()); } }
3. Auth Code:
import java.io.Serializable; import org.apache.shiro.SecurityUtils; 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 ShiroAuthService { public ShiroAuthService() { Factory factory = new IniSecurityManagerFactory( "classpath:shiro.ini"); SecurityManager securityManager = factory.getInstance(); // Make the SecurityManager instance available to the entire application // via static memory: SecurityUtils.setSecurityManager(securityManager); } public void testAuth() { // simulate a username/password (plaintext) token created in response to // a login attempt: UsernamePasswordToken token = new UsernamePasswordToken("user", "secret"); token.setRememberMe(true); boolean loggedIn = false; Session session = null; Subject currentUser = SecurityUtils.getSubject(); try { currentUser.login(token); session = currentUser.getSession(); System.out.println("Session Id: " + session.getId()); loggedIn = true; } catch (Exception ex) { loggedIn = false; } Serializable sessionId = session.getId(); if (loggedIn) { Subject requestSubject = new Subject.Builder().sessionId(sessionId) .buildSubject(); System.out.println("Is Authenticated = " + requestSubject.isAuthenticated());//Should return true System.out.println("Is Remembered = " + requestSubject.isRemembered()); } else { System.out.println("Not logged in."); } System.exit(0); } public static void main(String[] args) { new ShiroAuthService().testAuth(); } }
There are some other interesting features. It has a nice pluggable architecture wherein you can provide custom implementations of SessionManager, Realm, Caching, CredentialMatching, SessionDAO and "RememberMe".
For implementing a custom matcher, go with "public class CustomMatcher extends CodecSupport implements CredentialsMatcher". Similary, for a custom Realm implementation, use: "public class CustomRealm extends AuthenticatingRealm" as the base class provides some useful functionality. Of-course you can provide an implementation from scratch.
For more samples, see http://svn.apache.org/repos/asf/shiro/tags/shiro-root-1.2.1/samples/.
Published at DZone with permission of Nishant Chandra, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Trending
-
Getting Started With Istio in AWS EKS for Multicluster Setup
-
Introduction to Domain-Driven Design
-
Introduction to API Gateway in Microservices Architecture
-
Operator Overloading in Java
Comments