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<String> {
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 public Class<String> getCredentialType() {
069 return String.class;
070 }
071
072 @Override
073 public String getName() {
074 return "crowd";
075 }
076
077 @Override
078 public boolean authenticate(String username, String password) throws Exception {
079 // Username and passwords are required
080 if (username == null || username.isEmpty() || password == null || password.isEmpty()) {
081 log.log(Level.WARNING, "Unable to logon without username and password.");
082 return false;
083 }
084 try {
085 // Authenticate the user
086 if (log.isLoggable(Level.FINE)) {
087 log.log(Level.FINE, "Authenticating '" + username + "' on crowd directory");
088 }
089 getCrowdClient().authenticateUser(username, password);
090 return true;
091 } catch (InvalidAuthenticationException e) {
092 log.log(Level.WARNING, "Authentication failed for user '" + username + "'");
093 return false;
094 } catch (ApplicationPermissionException e) {
095 log.log(Level.SEVERE, "Application not authorized to authenticate user '" + username + "'", e);
096 return false;
097 }
098 }
099
100 @Override
101 public AuthenticationPlugin getImplementation() {
102 return this;
103 }
104 }