diff --git a/account/src/main/java/de/muehlencord/shared/account/shiro/realm/UserNameActiveDirectoryRealm.java b/account/src/main/java/de/muehlencord/shared/account/shiro/realm/UserNameActiveDirectoryRealm.java
index 97b0dbc..7f0b1a9 100644
--- a/account/src/main/java/de/muehlencord/shared/account/shiro/realm/UserNameActiveDirectoryRealm.java
+++ b/account/src/main/java/de/muehlencord/shared/account/shiro/realm/UserNameActiveDirectoryRealm.java
@@ -1,169 +1,179 @@
-/*
- * Copyright 2018 joern.muehlencord.
- *
- * Licensed 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.
- */
-package de.muehlencord.shared.account.shiro.realm;
-
-import java.util.HashSet;
-import java.util.Set;
-import javax.naming.NamingException;
-import javax.naming.ldap.LdapContext;
-import org.apache.shiro.authc.AuthenticationInfo;
-import org.apache.shiro.authc.AuthenticationToken;
-import org.apache.shiro.authc.UsernamePasswordToken;
-import org.apache.shiro.authz.AuthorizationInfo;
-import org.apache.shiro.realm.activedirectory.ActiveDirectoryRealm;
-import org.apache.shiro.realm.ldap.LdapContextFactory;
-import org.apache.shiro.realm.ldap.LdapUtils;
-import org.apache.shiro.subject.PrincipalCollection;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- *
- * @author joern.muehlencord
- */
-public class UserNameActiveDirectoryRealm extends ActiveDirectoryRealm {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(UserNameActiveDirectoryRealm.class);
-
- private boolean permissionsLookupEnabled = true;
- protected String fallbackPrincipalSuffix = null;
-
- @Override
- public boolean supports(AuthenticationToken token) {
- return (token != null && (UsernamePasswordToken.class.isAssignableFrom(token.getClass())));
- }
-
- @Override
- protected AuthenticationInfo queryForAuthenticationInfo(AuthenticationToken token, LdapContextFactory ldapContextFactory) throws NamingException {
- UsernamePasswordToken upToken = (UsernamePasswordToken) token;
-
- String userName = getUserName(upToken, principalSuffix);
- LdapContext ctx = null;
- try {
- ctx = lookupUser(userName, upToken.getCredentials(), ldapContextFactory);
- } catch (NamingException ex) {
- if (fallbackPrincipalSuffix == null) {
- throw ex;
- }
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Lookup with principalSuffix {} failed, falling back to {}", principalSuffix, fallbackPrincipalSuffix);
- }
- } finally {
- LdapUtils.closeContext(ctx);
- }
-
- if ((ctx == null) && (fallbackPrincipalSuffix != null)) {
- userName = getUserName(upToken, fallbackPrincipalSuffix);
- try {
- ctx = lookupUser(userName, upToken.getCredentials(), ldapContextFactory);
- } catch (NamingException ex) {
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Lookup with fallbackSuffix {} also failed", fallbackPrincipalSuffix);
- }
- throw ex;
- } finally {
- LdapUtils.closeContext(ctx);
- }
- }
-
- if (ctx == null) {
- throw new NamingException("Unknown error authenticationing user "+userName+". Context still null. Check implementation");
- }
-
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("User {} LDAP authenticated", userName);
- }
- LOGGER.debug("building authentication info");
- AuthenticationInfo authInfo = buildAuthenticationInfo(userName, upToken.getPassword());
-
- LOGGER.debug("authentifaction info created");
- return authInfo;
- }
-
- /**
- * Builds an {@link org.apache.shiro.authz.AuthorizationInfo} object by
- * querying the active directory LDAP context for the groups that a user is
- * a member of. The groups are then translated to role names by using the
- * configured {@link #groupRolesMap}.
- *
- * This implementation expects the principal argument to be a
- * String username.
- *
- * Subclasses can override this method to determine authorization data
- * (roles, permissions, etc) in a more complex way. Note that this default
- * implementation does not support permissions, only roles.
- *
- * @param principals the principal of the Subject whose account is being
- * retrieved.
- * @param ldapContextFactory the factory used to create LDAP connections.
- * @return the AuthorizationInfo for the given Subject principal.
- * @throws NamingException if an error occurs when searching the LDAP
- * server.
- */
- @Override
- protected AuthorizationInfo queryForAuthorizationInfo(PrincipalCollection principals, LdapContextFactory ldapContextFactory) throws NamingException {
- Set roleNames;
- if (this.permissionsLookupEnabled) {
- String username = (String) getAvailablePrincipal(principals);
- // Perform context search
- LdapContext ldapContext = ldapContextFactory.getSystemLdapContext();
- try {
- roleNames = getRoleNamesForUser(username, ldapContext);
- } finally {
- LdapUtils.closeContext(ldapContext);
- }
- } else {
- roleNames = new HashSet<>();
- }
- return buildAuthorizationInfo(roleNames);
- }
-
- public boolean isPermissionsLookupEnabled() {
- return permissionsLookupEnabled;
- }
-
- public void setPermissionsLookupEnabled(boolean permissionsLookupEnabled) {
- this.permissionsLookupEnabled = permissionsLookupEnabled;
- }
-
- public String getFallbackPrincipalSuffix() {
- return fallbackPrincipalSuffix;
- }
-
- public void setFallbackPrincipalSuffix(String fallbackPrincipalSuffix) {
- this.fallbackPrincipalSuffix = fallbackPrincipalSuffix;
- }
-
- private String getUserName(UsernamePasswordToken upToken, String suffix) {
- String userName = upToken.getUsername();
- if (suffix != null) {
- if (!userName.contains(suffix)) {
- userName += suffix;
- }
- }
- return userName;
- }
-
- private LdapContext lookupUser(String userName, Object credentials, LdapContextFactory ldapContextFactory) throws NamingException {
-
- // Binds using the username and password provided by the user.
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("start creating context");
- }
- return ldapContextFactory.getLdapContext(userName, credentials);
- }
-
-}
+/*
+ * Copyright 2018 joern.muehlencord.
+ *
+ * Licensed 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.
+ */
+package de.muehlencord.shared.account.shiro.realm;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import javax.naming.NamingException;
+import javax.naming.ldap.LdapContext;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.UsernamePasswordToken;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.realm.activedirectory.ActiveDirectoryRealm;
+import org.apache.shiro.realm.ldap.LdapContextFactory;
+import org.apache.shiro.realm.ldap.LdapUtils;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author joern.muehlencord
+ */
+public class UserNameActiveDirectoryRealm extends ActiveDirectoryRealm {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(UserNameActiveDirectoryRealm.class);
+
+ private boolean permissionsLookupEnabled = true;
+ protected List fallbackPrincipalSuffixes = null;
+ private NamingException lastException = null;
+
+ @Override
+ public boolean supports(AuthenticationToken token) {
+ return (token != null && (UsernamePasswordToken.class.isAssignableFrom(token.getClass())));
+ }
+
+ @Override
+ protected AuthenticationInfo queryForAuthenticationInfo(AuthenticationToken token, LdapContextFactory ldapContextFactory) throws NamingException {
+ UsernamePasswordToken upToken = (UsernamePasswordToken) token;
+ String userName = upToken.getUsername();
+ LdapContext ctx = lookupUserWithSuffix(upToken, ldapContextFactory, principalSuffix);
+
+ if (fallbackPrincipalSuffixes != null) {
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("Trying the fallbackSuffixes = {}", fallbackPrincipalSuffixes.toString());
+ }
+
+ Iterator it = fallbackPrincipalSuffixes.iterator();
+ while ((ctx == null) && (it.hasNext())) {
+ ctx = lookupUserWithSuffix(upToken, ldapContextFactory, it.next());
+ }
+ }
+
+ if (ctx == null) {
+ if (lastException != null) {
+ throw lastException;
+ } else {
+ throw new NamingException("Unknown error authenticationing user " + userName + ". Context still null. Check implementation");
+ }
+ }
+
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("User {} LDAP authenticated", userName);
+ LOGGER.debug("building authentication info");
+ }
+ AuthenticationInfo authInfo = buildAuthenticationInfo(userName, upToken.getPassword());
+
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("authentifaction info created");
+ }
+
+ return authInfo;
+ }
+
+ /**
+ * Builds an {@link org.apache.shiro.authz.AuthorizationInfo} object by querying the active directory LDAP context for the groups that a user is a member of. The groups are then translated to role
+ * names by using the configured {@link #groupRolesMap}.
+ *
+ * This implementation expects the principal argument to be a String username.
+ *
+ * Subclasses can override this method to determine authorization data (roles, permissions, etc) in a more complex way. Note that this default implementation does not support permissions, only
+ * roles.
+ *
+ * @param principals the principal of the Subject whose account is being retrieved.
+ * @param ldapContextFactory the factory used to create LDAP connections.
+ * @return the AuthorizationInfo for the given Subject principal.
+ * @throws NamingException if an error occurs when searching the LDAP server.
+ */
+ @Override
+ protected AuthorizationInfo queryForAuthorizationInfo(PrincipalCollection principals, LdapContextFactory ldapContextFactory) throws NamingException {
+ Set roleNames;
+ if (this.permissionsLookupEnabled) {
+ String username = (String) getAvailablePrincipal(principals);
+ // Perform context search
+ LdapContext ldapContext = ldapContextFactory.getSystemLdapContext();
+ try {
+ roleNames = getRoleNamesForUser(username, ldapContext);
+ } finally {
+ LdapUtils.closeContext(ldapContext);
+ }
+ } else {
+ roleNames = new HashSet<>();
+ }
+ return buildAuthorizationInfo(roleNames);
+ }
+
+ public boolean isPermissionsLookupEnabled() {
+ return permissionsLookupEnabled;
+ }
+
+ public void setPermissionsLookupEnabled(boolean permissionsLookupEnabled) {
+ this.permissionsLookupEnabled = permissionsLookupEnabled;
+ }
+
+ public List getFallbackPrincipalSuffixes() {
+ return fallbackPrincipalSuffixes;
+ }
+
+ public void setFallbackPrincipalSuffixes(List fallbackPrincipalSuffixes) {
+ this.fallbackPrincipalSuffixes = fallbackPrincipalSuffixes;
+ }
+
+ private String getUserName(UsernamePasswordToken upToken, String suffix) {
+ String userName = upToken.getUsername();
+ if (suffix != null) {
+ if (!userName.contains(suffix)) {
+ userName += suffix;
+ }
+ }
+ return userName;
+ }
+
+ private LdapContext lookupUser(String userName, Object credentials, LdapContextFactory ldapContextFactory) throws NamingException {
+
+ // Binds using the username and password provided by the user.
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("start creating context");
+ }
+ return ldapContextFactory.getLdapContext(userName, credentials);
+ }
+
+ private LdapContext lookupUserWithSuffix(UsernamePasswordToken upToken, LdapContextFactory ldapContextFactory, String currentSuffix) {
+ String userName = getUserName(upToken, currentSuffix);
+ LdapContext ctx = null;
+ try {
+ ctx = lookupUser(userName, upToken.getCredentials(), ldapContextFactory);
+ } catch (NamingException ex) {
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("Lookup with suffix {} failed", currentSuffix);
+ }
+ if (LOGGER.isTraceEnabled()) {
+ LOGGER.error(ex.getMessage());
+ LOGGER.trace("Detailed stacktrace", new Object[]{ex});
+ }
+
+ lastException = ex;
+ return null;
+ } finally {
+ LdapUtils.closeContext(ctx);
+ }
+ return ctx;
+ }
+
+}