@@ -45,6 +45,8 @@ public class LdapAuthenticator extends AdapterBase implements UserAuthenticator
4545 @ Inject
4646 private AccountManager _accountManager ;
4747
48+ private static final String LDAP_READ_TIMED_OUT_MESSAGE = "LDAP response read timed out" ;
49+
4850 public LdapAuthenticator () {
4951 super ();
5052 }
@@ -74,8 +76,8 @@ public Pair<Boolean, ActionOnFailedAuthentication> authenticate(final String use
7476 return rc ;
7577 }
7678 List <LdapTrustMapVO > ldapTrustMapVOs = getLdapTrustMapVOS (domainId );
77- if (ldapTrustMapVOs != null && ldapTrustMapVOs .size () > 0 ) {
78- if (ldapTrustMapVOs .size () == 1 && ldapTrustMapVOs .get (0 ).getAccountId () == 0 ) {
79+ if (ldapTrustMapVOs != null && ldapTrustMapVOs .size () > 0 ) {
80+ if (ldapTrustMapVOs .size () == 1 && ldapTrustMapVOs .get (0 ).getAccountId () == 0 ) {
7981 if (logger .isTraceEnabled ()) {
8082 logger .trace ("We have a single mapping of a domain to an ldap group or ou" );
8183 }
@@ -125,24 +127,24 @@ Pair<Boolean, ActionOnFailedAuthentication> authenticate(String username, String
125127 mappedGroups .retainAll (memberships );
126128 tracelist ("actual groups for " + username , mappedGroups );
127129 // check membership, there must be only one match in this domain
128- if (ldapUser .isDisabled ()) {
130+ if (ldapUser .isDisabled ()) {
129131 logAndDisable (userAccount , "attempt to log on using disabled ldap user " + userAccount .getUsername (), false );
130- } else if (mappedGroups .size () > 1 ) {
132+ } else if (mappedGroups .size () > 1 ) {
131133 logAndDisable (userAccount , "user '" + username + "' is mapped to more then one account in domain and will be disabled." , false );
132- } else if (mappedGroups .size () < 1 ) {
134+ } else if (mappedGroups .size () < 1 ) {
133135 logAndDisable (userAccount , "user '" + username + "' is not mapped to an account in domain and will be removed." , true );
134136 } else {
135137 // a valid ldap configured user exists
136138 LdapTrustMapVO mapping = _ldapManager .getLinkedLdapGroup (domainId ,mappedGroups .get (0 ));
137139 // we could now assert that ldapTrustMapVOs.contains(mapping);
138140 // createUser in Account can only be done by account name not by account id;
139141 Account account = _accountManager .getAccount (mapping .getAccountId ());
140- if (null == account ) {
142+ if (null == account ) {
141143 throw new CloudRuntimeException (String .format ("account for user (%s) not found by id %d" , username , mapping .getAccountId ()));
142144 }
143145 String accountName = account .getAccountName ();
144146 rc .first (_ldapManager .canAuthenticate (ldapUser .getPrincipal (), password , domainId ));
145- if (! rc .first ()) {
147+ if (!rc .first ()) {
146148 rc .second (ActionOnFailedAuthentication .INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT );
147149 }
148150 // for security reasons we keep processing on faulty login attempt to not give a way information on userid existence
@@ -162,7 +164,7 @@ Pair<Boolean, ActionOnFailedAuthentication> authenticate(String username, String
162164 userAccount = _accountManager .getUserAccountById (user .getId ());
163165 } else {
164166 // not a new user, check if mapped group has changed
165- if (userAccount .getAccountId () != mapping .getAccountId ()) {
167+ if (userAccount .getAccountId () != mapping .getAccountId ()) {
166168 final Account mappedAccount = _accountManager .getAccount (mapping .getAccountId ());
167169 if (mappedAccount == null || mappedAccount .getRemoved () != null ) {
168170 throw new CloudRuntimeException ("Mapped account for users does not exist. Please contact your administrator." );
@@ -174,12 +176,21 @@ Pair<Boolean, ActionOnFailedAuthentication> authenticate(String username, String
174176 }
175177 } catch (NoLdapUserMatchingQueryException e ) {
176178 logger .debug (e .getMessage ());
177- disableUserInCloudStack (userAccount );
179+ processLdapUserErrorMessage (userAccount , e . getMessage (), rc );
178180 }
179181
180182 return rc ;
181183 }
182184
185+ private void processLdapUserErrorMessage (UserAccount user , String errorMessage , Pair <Boolean , ActionOnFailedAuthentication > rc ) {
186+ if (StringUtils .isNotEmpty (errorMessage ) && errorMessage .contains (LDAP_READ_TIMED_OUT_MESSAGE ) && !rc .first ()) {
187+ rc .second (ActionOnFailedAuthentication .INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT );
188+ } else {
189+ // no user in ldap ==>> disable user in cloudstack
190+ disableUserInCloudStack (user );
191+ }
192+ }
193+
183194 private void tracelist (String msg , List <String > listToTrace ) {
184195 if (logger .isTraceEnabled ()) {
185196 StringBuilder logMsg = new StringBuilder ();
@@ -197,7 +208,7 @@ private void logAndDisable(UserAccount userAccount, String msg, boolean remove)
197208 if (logger .isInfoEnabled ()) {
198209 logger .info (msg );
199210 }
200- if (remove ) {
211+ if (remove ) {
201212 removeUserInCloudStack (userAccount );
202213 } else {
203214 disableUserInCloudStack (userAccount );
@@ -229,23 +240,22 @@ private Pair<Boolean, ActionOnFailedAuthentication> authenticate(String username
229240 processLdapUser (password , domainId , user , rc , ldapUser , accountType );
230241 } catch (NoLdapUserMatchingQueryException e ) {
231242 logger .debug (e .getMessage ());
232- // no user in ldap ==>> disable user in cloudstack
233- disableUserInCloudStack (user );
243+ processLdapUserErrorMessage (user , e .getMessage (), rc );
234244 }
235245 return rc ;
236246 }
237247
238248 private void processLdapUser (String password , Long domainId , UserAccount user , Pair <Boolean , ActionOnFailedAuthentication > rc , LdapUser ldapUser , Account .Type accountType ) {
239- if (!ldapUser .isDisabled ()) {
249+ if (!ldapUser .isDisabled ()) {
240250 rc .first (_ldapManager .canAuthenticate (ldapUser .getPrincipal (), password , domainId ));
241- if (rc .first ()) {
242- if (user == null ) {
251+ if (rc .first ()) {
252+ if (user == null ) {
243253 // import user to cloudstack
244254 createCloudStackUserAccount (ldapUser , domainId , accountType );
245255 } else {
246256 enableUserInCloudStack (user );
247257 }
248- } else if (user != null ) {
258+ } else if (user != null ) {
249259 rc .second (ActionOnFailedAuthentication .INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT );
250260 }
251261 } else {
@@ -264,30 +274,34 @@ private void processLdapUser(String password, Long domainId, UserAccount user, P
264274 */
265275 Pair <Boolean , ActionOnFailedAuthentication > authenticate (String username , String password , Long domainId , UserAccount user ) {
266276 boolean result = false ;
277+ boolean timedOut = false ;
267278
268- if (user != null ) {
279+ if (user != null ) {
269280 try {
270281 LdapUser ldapUser = _ldapManager .getUser (username , domainId );
271- if (!ldapUser .isDisabled ()) {
282+ if (!ldapUser .isDisabled ()) {
272283 result = _ldapManager .canAuthenticate (ldapUser .getPrincipal (), password , domainId );
273284 } else {
274285 logger .debug ("user with principal " + ldapUser .getPrincipal () + " is disabled in ldap" );
275286 }
276287 } catch (NoLdapUserMatchingQueryException e ) {
277288 logger .debug (e .getMessage ());
289+ if (e .getMessage ().contains (LDAP_READ_TIMED_OUT_MESSAGE )) {
290+ timedOut = true ;
291+ }
278292 }
279293 }
280- return processResultAndAction (user , result );
294+ return processResultAndAction (user , result , timedOut );
281295 }
282296
283- private Pair <Boolean , ActionOnFailedAuthentication > processResultAndAction (UserAccount user , boolean result ) {
284- return (!result && user != null ) ?
297+ private Pair <Boolean , ActionOnFailedAuthentication > processResultAndAction (UserAccount user , boolean result , boolean timedOut ) {
298+ return (!result && ( user != null || timedOut ) ) ?
285299 new Pair <Boolean , ActionOnFailedAuthentication >(result , ActionOnFailedAuthentication .INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT ):
286300 new Pair <Boolean , ActionOnFailedAuthentication >(result , null );
287301 }
288302
289303 private void enableUserInCloudStack (UserAccount user ) {
290- if (user != null && (user .getState ().equalsIgnoreCase (Account .State .DISABLED .toString ()))) {
304+ if (user != null && (user .getState ().equalsIgnoreCase (Account .State .DISABLED .toString ()))) {
291305 _accountManager .enableUser (user .getId ());
292306 }
293307 }
0 commit comments