Download and Install
Download for Apache Shiro: http://shiro.apache.org/download.html ; I used Shrio-All (1.2.2 Binary Distribution) http://tweedo.com/mirror/apache/shiro/1.2.2/shiro-root-1.2.2-source-release.zip
After downloading, include shiro-all-1.2.2.jar in the lib folder. 
We can also include other .jar files that we will need later.
Remember to add your jars to the build path.
web.xml
Add this to your web.xml
<listener> <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class> </listener> <filter> <filter-name>ShiroFilter</filter-name> <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class> </filter> <filter-mapping> <filter-name>ShiroFilter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> <dispatcher>INCLUDE</dispatcher> <dispatcher>ERROR</dispatcher> </filter-mapping>
shiro.ini
Put your shiro.ini in WEB-INF:
[main] authc.loginUrl = /Login.html?gwt.codesvr=127.0.0.1:9997 authc.successUrl = /Leitfaden.html logout.redirectUrl = /login.html # ------------------------ # Database # Own Realm jdbcRealm = leitfaden.login.server.MyRealm # Sha256 sha256Matcher = org.apache.shiro.authc.credential.Sha256CredentialsMatcher # base64 encoding, not hex in this example: sha256Matcher.storedCredentialsHexEncoded = false sha256Matcher.hashIterations = 1024 jdbcRealm.credentialsMatcher = $sha256Matcher # User Query # default is "select password from users where username = ?" jdbcRealm.authenticationQuery = SELECT password, salt FROM USER WHERE email = ? # Connection ds = com.mysql.jdbc.jdbc2.optional.MysqlDataSource ds.serverName = localhost ds.user = root ds.password = root ds.databaseName = leitfaden jdbcRealm.dataSource=$ds authc.usernameParam = email authc.passwordParam = password authc.failureKeyAttribute = shiroLoginFailure # Use Built-in Chache Manager builtInCacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager securityManager.cacheManager = $builtInCacheManager # ----------------------------------------------------------------------------- [urls] /yourMainUrl.html = authc
GWT module
Create a module for logging in. The name of the Login module and the name of the package leitfaden.login:
Add this to your web.xml
<servlet> <servlet-name>LoginService</servlet-name> <servlet-class>leitfaden.login.server.LoginServiceImpl</servlet-class> </servlet> <servlet-mapping> <servlet-name>LoginService</servlet-name> <url-pattern>/leitfaden.login.Login/LoginService</url-pattern> </servlet-mapping>
LoginService.java
@RemoteServiceRelativePath("LoginService") public interface LoginService extends RemoteService { public Boolean isLoggedIn(); public Boolean tryLogin(String email, String password, Boolean rememberMe); public void logout(); public void registrate(String email, String password); }
LoginServiceAsync.java
public interface LoginServiceAsync { public void isLoggedIn(AsyncCallback<Boolean> callback); public void tryLogin(String email, String password, Boolean rememberMe, AsyncCallback<Boolean> callback); public void logout(AsyncCallback<Void> callback); public void registrate(String email, String password, AsyncCallback<Void> callback); }
LoginServiceImpl
public class LoginServiceImpl extends RemoteServiceServlet implements LoginService { private static final long serialVersionUID = -4051026136441981243L; private static final transient Logger log = LoggerFactory .getLogger(LoginServiceImpl.class); private org.apache.shiro.subject.Subject currentUser; public LoginServiceImpl() { Factory<SecurityManager> factory = new IniSecurityManagerFactory(); SecurityManager securityManager = factory.getInstance(); SecurityUtils.setSecurityManager(securityManager); } @Override public Boolean isLoggedIn() { currentUser = SecurityUtils.getSubject(); if (currentUser.isAuthenticated()) { return true; } else { return false; } } @Override public Boolean tryLogin(String username, String password, Boolean rememberMe) {
MyRealm.java
Now users can register in this application. But Ciro does not know how to compare salted passwords with a given user. To do this, we need to realize our own kingdom. Realm is essentially a DAO .
MyRealm.java receives the user with the given email address and returns SaltedAuthenticationInfo. With this, SaltedAuthenticationInfo Shiro knows how to compare user input with user from the database.
public class MyRealm extends JdbcRealm { private static final Logger log = LoggerFactory.getLogger(MyRealm.class); @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { // identify account to log to UsernamePasswordToken userPassToken = (UsernamePasswordToken) token; final String username = userPassToken.getUsername(); if (username == null) { log.debug("Username is null."); return null; } // read password hash and salt from db final PasswdSalt passwdSalt = getPasswordForUser(username); if (passwdSalt == null) { log.debug("No account found for user [" + username + "]"); return null; } // return salted credentials SaltedAuthenticationInfo info = new MySaltedAuthentificationInfo(username, passwdSalt.password, passwdSalt.salt); return info; } private PasswdSalt getPasswordForUser(String username) { User user = getUserByEmail(username); if (user == null) { return null; } return new PasswdSalt(user.getPassword(), user.getSalt()); } private User getUserByEmail(String email) { UserDAL.connect(); User user = new UserDAL().getUserByEmail(email); UserDAL.disconnect(); return user; } class PasswdSalt { public String password; public String salt; public PasswdSalt(String password, String salt) { super(); this.password = password; this.salt = salt; } } }
MySaltedAuthentificationInfo The important thing is that you correctly decode the salt in getCredentialsSalt (). I used Base64.
public class MySaltedAuthentificationInfo implements SaltedAuthenticationInfo { private static final long serialVersionUID = -2342452442602696063L; private String username; private String password; private String salt; public MySaltedAuthentificationInfo(String username, String password, String salt) { this.username = username; this.password = password; this.salt = salt; } @Override public PrincipalCollection getPrincipals() { PrincipalCollection coll = new SimplePrincipalCollection(username, username); return coll; } @Override public Object getCredentials() { return password; } @Override public ByteSource getCredentialsSalt() { return new SimpleByteSource(Base64.decode(salt)); } }
Now users can register and log in. You will only need a code representation in the login module that calls LoginService.