001 package org.crsh.plugins.crowd;
002
003 import com.atlassian.crowd.exception.ApplicationPermissionException;
004 import com.atlassian.crowd.exception.InvalidAuthenticationException;
005 import com.atlassian.crowd.integration.rest.service.factory.RestCrowdClientFactory;
006 import com.atlassian.crowd.service.client.ClientProperties;
007 import com.atlassian.crowd.service.client.ClientPropertiesImpl;
008 import com.atlassian.crowd.service.client.ClientResourceLocator;
009 import com.atlassian.crowd.service.client.CrowdClient;
010 import org.crsh.auth.AuthenticationPlugin;
011 import org.crsh.plugin.CRaSHPlugin;
012
013 import java.util.logging.Level;
014 import java.util.logging.Logger;
015
016 /**
017 * Allows to use an Atlassian Crowd serer to authenticate on CRaSH
018 * To use it you need to :
019 * <ul>
020 * <li>Define the application on the crowd server side,</li>
021 * <li>Use <pre>crash.auth=crowd</pre> in your crash.properties configuration file,</li>
022 * <li>Create the <a href="https://confluence.atlassian.com/display/CROWD/The+crowd.properties+File"><pre>crowd.properties</pre> configuration file</a>
023 * and add it in your application classpath or by defining its path with the system property crowd.properties (<pre>-Dcrowd.properties={FILE-PATH}/crowd.properties</pre>).</li>
024 * </ul>
025 */
026 public class CrowdAuthenticationPlugin extends
027 CRaSHPlugin<AuthenticationPlugin> implements
028 AuthenticationPlugin {
029
030 /**
031 * Logger
032 */
033 protected final Logger log = Logger.getLogger(getClass().getName());
034
035 /**
036 * Crowd client instance
037 */
038 private static volatile CrowdClient crowdClient;
039
040 /**
041 * Lock to create the crowd client
042 */
043 private static final Object lock = new Object();
044
045 /**
046 * Get a ready to use CrowdClient.
047 *
048 * @return a CrowdClient already initialized
049 */
050 private static CrowdClient getCrowdClient() {
051 if (crowdClient == null) {
052 synchronized (lock) {
053 if (crowdClient == null) {
054 ClientResourceLocator
055 crl = new ClientResourceLocator("crowd.properties");
056 if (crl.getProperties() == null) {
057 throw new NullPointerException("crowd.properties can not be found in classpath");
058 }
059 ClientProperties clientProperties = ClientPropertiesImpl.newInstanceFromResourceLocator(crl);
060 RestCrowdClientFactory restCrowdClientFactory = new RestCrowdClientFactory();
061 crowdClient = restCrowdClientFactory.newInstance(clientProperties);
062 }
063 }
064 }
065 return crowdClient;
066 }
067
068 @Override
069 public String getName() {
070 return "crowd";
071 }
072
073 @Override
074 public boolean authenticate(String username, String password) throws Exception {
075 // Username and passwords are required
076 if (username == null || username.isEmpty() || password == null || password.isEmpty()) {
077 log.log(Level.WARNING, "Unable to logon without username and password.");
078 return false;
079 }
080 try {
081 // Authenticate the user
082 if (log.isLoggable(Level.FINE)) {
083 log.log(Level.FINE, "Authenticating '" + username + "' on crowd directory");
084 }
085 getCrowdClient().authenticateUser(username, password);
086 return true;
087 } catch (InvalidAuthenticationException e) {
088 log.log(Level.WARNING, "Authentication failed for user '" + username + "'");
089 return false;
090 } catch (ApplicationPermissionException e) {
091 log.log(Level.SEVERE, "Application not authorized to authenticate user '" + username + "'", e);
092 return false;
093 }
094 }
095
096 @Override
097 public AuthenticationPlugin getImplementation() {
098 return this;
099 }
100 }