From 118878eb12c8e142da7648cae3880754b34798b2 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Thu, 30 Jun 2011 20:11:15 +0000 Subject: [PATCH] Fix issue with username case in LDAP Improve log in mechanism in RAP git-svn-id: https://svn.argeo.org/commons/trunk@4643 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- .../main/java/org/argeo/eclipse/ui/Error.java | 11 +- .../META-INF/spring/ldap.xml | 29 +++-- .../branding/default.htm | 14 +++ .../branding/favicon.ico | Bin 0 -> 4286 bytes .../build.properties | 3 +- .../org.argeo.security.ui.rap/plugin.xml | 12 ++ .../security/ui/rap/SecureEntryPoint.java | 108 ++++++++++++------ .../ui/dialogs/AbstractLoginDialog.java | 21 ++-- security/plugins/pom.xml | 1 + .../core/KeyBasedSystemExecutionService.java | 2 + .../ldap/jcr/JcrUserDetailsContextMapper.java | 15 ++- 11 files changed, 155 insertions(+), 61 deletions(-) create mode 100644 security/plugins/org.argeo.security.ui.rap/branding/default.htm create mode 100644 security/plugins/org.argeo.security.ui.rap/branding/favicon.ico diff --git a/eclipse/runtime/org.argeo.eclipse.ui/src/main/java/org/argeo/eclipse/ui/Error.java b/eclipse/runtime/org.argeo.eclipse.ui/src/main/java/org/argeo/eclipse/ui/Error.java index 96724adff..04971d155 100644 --- a/eclipse/runtime/org.argeo.eclipse.ui/src/main/java/org/argeo/eclipse/ui/Error.java +++ b/eclipse/runtime/org.argeo.eclipse.ui/src/main/java/org/argeo/eclipse/ui/Error.java @@ -26,6 +26,11 @@ public class Error extends TitleAreaDialog { private final Throwable exception; public static void show(String message, Throwable e) { + // rethrow ThreaDeath in order to make sure that RAP will properly clean + // up the UI thread + if (e instanceof ThreadDeath) + throw (ThreadDeath) e; + new Error(getDisplay().getActiveShell(), message, e).open(); } @@ -36,7 +41,11 @@ public class Error extends TitleAreaDialog { /** Tries to find a display */ private static Display getDisplay() { try { - return PlatformUI.getWorkbench().getDisplay(); + Display display = PlatformUI.getWorkbench().getDisplay(); + if (display != null) + return display; + else + return Display.getDefault(); } catch (Exception e) { return Display.getCurrent(); } diff --git a/security/modules/org.argeo.security.dao.ldap/META-INF/spring/ldap.xml b/security/modules/org.argeo.security.dao.ldap/META-INF/spring/ldap.xml index 33dc554a8..1f2117d1a 100644 --- a/security/modules/org.argeo.security.dao.ldap/META-INF/spring/ldap.xml +++ b/security/modules/org.argeo.security.dao.ldap/META-INF/spring/ldap.xml @@ -33,30 +33,29 @@ + + + + + + + + + + + + class="org.springframework.security.providers.ldap.authenticator.PasswordComparisonAuthenticator"> + + - - - - - - - - - - - - - diff --git a/security/plugins/org.argeo.security.ui.rap/branding/default.htm b/security/plugins/org.argeo.security.ui.rap/branding/default.htm new file mode 100644 index 000000000..67c89f4fe --- /dev/null +++ b/security/plugins/org.argeo.security.ui.rap/branding/default.htm @@ -0,0 +1,14 @@ + + + +
+ + + + +
+ Login... +
+
+ + \ No newline at end of file diff --git a/security/plugins/org.argeo.security.ui.rap/branding/favicon.ico b/security/plugins/org.argeo.security.ui.rap/branding/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..213cdf73f443f7923187a156e3a6a4d9c9beb995 GIT binary patch literal 4286 zcmbW4drXye7{`yn#Q5sQT~#ADdOg9k?+IB;NbS67#F&z?OW zc6N6D*xufLYsZcqw_00UFEuwepK5Aq+Sbs}kiBu^#ur8ZLn8N!+$S@GgFYMjB7s7;aP+wn<+S*#w)YQOcv+3Dxw?p`FyWN)>8ymODy-0yREJ8bmWW%vz z$3`AKdbHy3;lo$<@86G(jt=FLDeJ@9wQG@|pN|zQR;a98xl+Fu6&30IEnBw0>2zKb zJKvROCkg*Sk>Ph^hp>Z%?GZM*ySsJGTvtU!1y-+Kjm*qUBqb#wE-nu9=g&t>OpKo6 z!F7wA z7Ct22*tKgH>gwvSe*Jo6Wo04e^+lMvd@Cjtoxr%V(_Z-kFRVF)sTnm03X4{of`fzA zj(PLuAu%yg?WT^+n>T-3SXh`KP^l8Np)V(dJ5t0$w&Wak@7@iU%Y_XaHXvhp0cI3- zW26grlqtpUAtW|c{X-vxhlgvN7!z-9d?Y@cDSY~YvCu=<6(TrtdCv9&LXvXT7qo%-${dnB_*Lp9QPA`O`F5_IeCE6K5|mZdVobyJduAIp(Egdr z>(m$Y0pq~B5Z|^5`U&BV66q!1h&yY|TKn~Y>``@pBB0_VQYv?&z|oDB&8M(%`}YGr zPg{cX-AGPO)?QIwUJmI`mrF`YCJQ%(Y_45;tk(J)cF%yi#%wx^(744~=Q%k!nxE`@ z^jX6$4-#6>o4z}y;Re!*wrDN!dFk7fOkq0=KKmT?OmhBau0z-}LnAPI_G}on#k!Q5 zLRD3j_FkC~GQ0(c0_i3w}>aOS`S_rnx^?8|aH=ZD%yM8DsWV#@oxj>B}GQy6I=Pv3}q4 zM8_|P&Z!1_KKbm)oCEC7%yIVJbrm*Poflzi+M_ki+G38A?d6l*$A71DVBh<)eLqjD zIg16E1z;SaqN3Ce)*0uMksH!?neW)SbEo>iXZ>XN`M;|3Bh$4{$#x@Pb-VO~8>aVZ z&#bqOAuc&xeGwKG)>rR~7A-<*QchsgMxx|JzNWGEzjPC zVE1LyXKBaS+AEkApNr|!rz0RBKz+hJ17{icPRw&JpX?N}DZJ(zTjO)!yd<6N%y-TZ z+Q79eb@t#T*B_?us6WTwIKj@@mA{j$^EI;M`#D(Er>gwzakC-a=TtWcQyxIUQ&H_~Y$Y5f-yheLx%7 zf0*y==d5{3Yv*&Z~%zc%toh+-uz5nF9?muWlZs&J?e6C}3 z{dEN8y0rIlp3?^IwI(lf4ak1keh%CVb1pFM-rBG5W%ILeb^k>^^B}qXqNxo=PEM*k zgBLb^1d*Jup!-kSz&M1p{4${K{w%ZaS&bj)oaMT` z?9-w<*o=jU7YzW-?5tMyq9aDi+wUhggv`Qgmd$zSNNIN zc#qF$U%ML)N-cq~Sf2S;exKfy->1LJ@8n*2vBxW=a;6ORC>1@F9??nZ75$?7F=3EJ JCeSk+{{dc%*&6@= literal 0 HcmV?d00001 diff --git a/security/plugins/org.argeo.security.ui.rap/build.properties b/security/plugins/org.argeo.security.ui.rap/build.properties index b840a9456..572b0b491 100644 --- a/security/plugins/org.argeo.security.ui.rap/build.properties +++ b/security/plugins/org.argeo.security.ui.rap/build.properties @@ -1,4 +1,5 @@ bin.includes = plugin.xml,\ - META-INF/ + META-INF/,\ + branding/ source.. = src/main/java/ output.. = target/classes/ diff --git a/security/plugins/org.argeo.security.ui.rap/plugin.xml b/security/plugins/org.argeo.security.ui.rap/plugin.xml index 9d6135fea..7e192647d 100644 --- a/security/plugins/org.argeo.security.ui.rap/plugin.xml +++ b/security/plugins/org.argeo.security.ui.rap/plugin.xml @@ -22,4 +22,16 @@ + + + + + diff --git a/security/plugins/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/SecureEntryPoint.java b/security/plugins/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/SecureEntryPoint.java index 4d85cc869..8e377e099 100644 --- a/security/plugins/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/SecureEntryPoint.java +++ b/security/plugins/org.argeo.security.ui.rap/src/main/java/org/argeo/security/ui/rap/SecureEntryPoint.java @@ -7,6 +7,7 @@ import javax.security.auth.login.LoginException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.argeo.ArgeoException; import org.eclipse.equinox.security.auth.ILoginContext; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.rwt.RWT; @@ -51,37 +52,60 @@ public class SecureEntryPoint implements IEntryPoint { final ILoginContext loginContext = SecureRapActivator .createLoginContext(); Subject subject = null; - tryLogin: while (subject == null) { + tryLogin: while (subject == null && !display.isDisposed()) { try { loginContext.login(); subject = loginContext.getSubject(); } catch (LoginException e) { - if (e.getCause() != null) { - Throwable firstCause = e.getCause(); - // log.error("Cause", firstCause); - if (firstCause instanceof LoginException - && firstCause.getCause() != null) { - Throwable secondCause = firstCause.getCause(); - if (secondCause instanceof BadCredentialsException) { - MessageDialog.openInformation( - display.getActiveShell(), - "Bad Credentials", - "Your credentials are incorrect"); - // retry login - continue tryLogin; - } else if (secondCause instanceof ThreadDeath) { - // rethrow thread death caused by dialog UI timeout - throw (ThreadDeath) secondCause; - } - - } else if (firstCause instanceof ThreadDeath) { - throw (ThreadDeath) firstCause; - } + BadCredentialsException bce = wasCausedByBadCredentials(e); + if (bce != null) { + MessageDialog.openInformation(display.getActiveShell(), + "Bad Credentials", bce.getMessage()); + // retry login + continue tryLogin; + } + + // check thread death + ThreadDeath td = wasCausedByThreadDeath(e); + if (td != null) { + display.dispose(); + throw td; + } + + // if (e.getCause() != null) { + // Throwable firstCause = e.getCause(); + // // log.error("Cause", firstCause); + // if (firstCause instanceof LoginException + // && firstCause.getCause() != null) { + // Throwable secondCause = firstCause.getCause(); + // if (secondCause instanceof BadCredentialsException) { + // MessageDialog.openInformation( + // display.getActiveShell(), + // "Bad Credentials", + // "Your credentials are incorrect"); + // // retry login + // continue tryLogin; + // } else if (secondCause instanceof ThreadDeath) { + // // rethrow thread death caused by dialog UI timeout + // throw (ThreadDeath) secondCause; + // } + // + // } else if (firstCause instanceof ThreadDeath) { + // throw (ThreadDeath) firstCause; + // } + // } + + if (!display.isDisposed()) { + org.argeo.eclipse.ui.Error.show( + "Unexpected exception during authentication", e); + // this was not just bad credentials or death thread + RWT.getRequest().getSession().setMaxInactiveInterval(1); + display.dispose(); + return -1; + } else { + throw new ArgeoException( + "Unexpected exception during authentication", e); } - // this was not just bad credentials returns - RWT.getRequest().getSession().setMaxInactiveInterval(1); - display.dispose(); - return -1; } } @@ -99,13 +123,6 @@ public class SecureEntryPoint implements IEntryPoint { public void run() { log.debug("Display disposed"); logout(loginContext, username); - // invalidate session - //RWT.getRequest().getSession().setMaxInactiveInterval(1); - try { - Thread.sleep(2000); - } catch (InterruptedException e1) { - // silent - } } }); @@ -121,6 +138,31 @@ public class SecureEntryPoint implements IEntryPoint { return processReturnCode(returnCode); } + /** Recursively look for {@link BadCredentialsException} in the root causes. */ + private BadCredentialsException wasCausedByBadCredentials(Throwable t) { + if (t instanceof BadCredentialsException) + return (BadCredentialsException) t; + + if (t.getCause() != null) + return wasCausedByBadCredentials(t.getCause()); + else + return null; + } + + /** + * If there is a {@link ThreadDeath} in the root causes, rethrow it + * (important for RAP cleaning mechanism) + */ + protected ThreadDeath wasCausedByThreadDeath(Throwable t) { + if (t instanceof ThreadDeath) + return (ThreadDeath) t; + + if (t.getCause() != null) + return wasCausedByThreadDeath(t.getCause()); + else + return null; + } + protected void logout(ILoginContext secureContext, String username) { try { secureContext.logout(); diff --git a/security/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/dialogs/AbstractLoginDialog.java b/security/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/dialogs/AbstractLoginDialog.java index 92ca3d85d..fecb80afc 100644 --- a/security/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/dialogs/AbstractLoginDialog.java +++ b/security/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/dialogs/AbstractLoginDialog.java @@ -124,10 +124,10 @@ public abstract class AbstractLoginDialog extends TrayDialog implements // when the OSGi runtime is shut down try { Thread.sleep(100); - if (display.isDisposed()) { - log.warn("Display is disposed, killing login dialog thread"); - throw new ThreadDeath(); - } + // if (display.isDisposed()) { + // log.warn("Display is disposed, killing login dialog thread"); + // throw new ThreadDeath(); + // } } catch (final Exception e) { // do nothing } @@ -147,6 +147,7 @@ public abstract class AbstractLoginDialog extends TrayDialog implements }, true, new NullProgressMonitor(), Display.getDefault()); } catch (ThreadDeath e) { isCancelled = true; + log.debug("Thread " + Thread.currentThread().getId() + " died"); throw e; } catch (Exception e) { isCancelled = true; @@ -157,12 +158,12 @@ public abstract class AbstractLoginDialog extends TrayDialog implements } finally { // so that the modal thread dies processCallbacks = true; - try { - // wait for the modal context thread to gracefully exit - modalContextThread.join(1000); - } catch (InterruptedException ie) { - // silent - } + // try { + // // wait for the modal context thread to gracefully exit + // modalContextThread.join(); + // } catch (InterruptedException ie) { + // // silent + // } modalContextThread = null; } } diff --git a/security/plugins/pom.xml b/security/plugins/pom.xml index b24f6fc27..775893108 100644 --- a/security/plugins/pom.xml +++ b/security/plugins/pom.xml @@ -27,6 +27,7 @@ plugin.xml META-INF/** + branding/** jaas/** icons/** diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/KeyBasedSystemExecutionService.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/KeyBasedSystemExecutionService.java index 07ae04653..b5791c587 100644 --- a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/KeyBasedSystemExecutionService.java +++ b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/KeyBasedSystemExecutionService.java @@ -17,6 +17,8 @@ public class KeyBasedSystemExecutionService extends AbstractSystemExecution public void execute(Runnable runnable) { try { wrapWithSystemAuthentication(Executors.callable(runnable)).call(); + } catch (RuntimeException e) { + throw e; } catch (Exception e) { throw new ArgeoException( "Exception when running system authenticated task", e); diff --git a/security/runtime/org.argeo.security.ldap/src/main/java/org/argeo/security/ldap/jcr/JcrUserDetailsContextMapper.java b/security/runtime/org.argeo.security.ldap/src/main/java/org/argeo/security/ldap/jcr/JcrUserDetailsContextMapper.java index 5c6a88585..537e01763 100644 --- a/security/runtime/org.argeo.security.ldap/src/main/java/org/argeo/security/ldap/jcr/JcrUserDetailsContextMapper.java +++ b/security/runtime/org.argeo.security.ldap/src/main/java/org/argeo/security/ldap/jcr/JcrUserDetailsContextMapper.java @@ -22,6 +22,7 @@ import org.argeo.jcr.JcrUtils; import org.argeo.security.jcr.JcrUserDetails; import org.springframework.ldap.core.DirContextAdapter; import org.springframework.ldap.core.DirContextOperations; +import org.springframework.security.BadCredentialsException; import org.springframework.security.GrantedAuthority; import org.springframework.security.context.SecurityContextHolder; import org.springframework.security.providers.encoding.PasswordEncoder; @@ -108,13 +109,25 @@ public class JcrUserDetailsContextMapper implements UserDetailsContextMapper, /** @return path to the user home node */ protected String mapLdapToJcr(String username, DirContextOperations ctx) { + String usernameLdap = ctx.getStringAttribute(usernameAttribute); + // log.debug("username=" + username + ", usernameLdap=" + usernameLdap); + if (!username.equals(usernameLdap)) { + String msg = "Provided username '" + username + + "' is different from username stored in LDAP '" + + usernameLdap+"'"; + // we log it because the exception may not be displayed + log.error(msg); + throw new BadCredentialsException(msg); + } + try { + Node userHome = JcrUtils.getUserHome(session, username); if (userHome == null) userHome = JcrUtils.createUserHome(session, homeBasePath, username); String userHomePath = userHome.getPath(); - Node userProfile; // = userHome.getNode(ARGEO_PROFILE); + Node userProfile; // = userHome.getNode(ARGEO_PROFILE); if (userHome.hasNode(ARGEO_PROFILE)) { userProfile = userHome.getNode(ARGEO_PROFILE); } else { -- 2.30.2