package com.airbnb.shiro; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authz.AuthorizationException; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.Permission; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.ldap.UnsupportedAuthenticationMechanismException; import org.apache.shiro.realm.ldap.JndiLdapContextFactory; import org.apache.shiro.realm.ldap.JndiLdapRealm; import org.apache.shiro.subject.PrincipalCollection; import org.joda.time.Duration; import javax.naming.AuthenticationNotSupportedException; import javax.naming.NamingException; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Set; @Slf4j public class ExampleLDAPRealm extends JndiLdapRealm { @Setter private List<UserGroup> groups = Collections.emptyList(); private JndiLdapContextFactory lcf; private static String REALM_NAME = ExampleLDAPRealm.class.getSimpleName(); public ExampleLDAPRealm() { this.setUserDnTemplate("Default DN template"); lcf = new JndiLdapContextFactory(); lcf.setSystemUsername("System username that will be used when creating an LDAP connection"); lcf.setSystemPassword("System Password for the username used to create LDAP connection "); lcf.setAuthenticationMechanism("simple"); lcf.setUrl("LDAP URL"); this.setContextFactory(lcf); } @Override public void setName(String name) {} @Override public String getName() { return REALM_NAME; } @Override public boolean supports(AuthenticationToken token) { return (token instanceof UsernamePasswordToken); } @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { Set<String> roles = Sets.newHashSet("user"); Set<Permission> permissions = Sets.newHashSet(); Collection<AllowAllUser> principalsCollection = principals.byType(AllowAllUser.class); if (principalsCollection.isEmpty()) { throw new AuthorizationException("No principals!"); } for (AllowAllUser user : principalsCollection) { for (UserGroup userGroup : groups) { if (userGroup.representedByGroupStrings(user.getGroups())) { permissions.addAll(userGroup.getPermissions()); break; } } } SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(roles); authorizationInfo.setObjectPermissions(permissions); return authorizationInfo; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token; try { queryForAuthenticationInfo(usernamePasswordToken, getContextFactory()); } catch (AuthenticationNotSupportedException e) { throw new UnsupportedAuthenticationMechanismException("Unsupported configured authentication mechanism", e); } catch (javax.naming.AuthenticationException e) { throw new AuthenticationException("LDAP authentication failed.", e); } catch (NamingException e) { throw new AuthenticationException("LDAP naming error while attempting to authenticate user.", e); } return new SimpleAuthenticationInfo(token.getPrincipal(), token.getCredentials(), ExampleLDAPRealm.class.getSimpleName()); } }