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());
}
}