PageRenderTime 28ms CodeModel.GetById 11ms app.highlight 12ms RepoModel.GetById 2ms app.codeStats 0ms

/hudson-core/src/main/java/hudson/cli/ClientAuthenticationCache.java

http://github.com/hudson/hudson
Java | 126 lines | 79 code | 14 blank | 33 comment | 4 complexity | 7f6163305a5c079af5fa84629da46155 MD5 | raw file
  1package hudson.cli;
  2
  3import hudson.FilePath;
  4import hudson.FilePath.FileCallable;
  5import hudson.model.Hudson;
  6import hudson.model.Hudson.MasterComputer;
  7import hudson.os.PosixAPI;
  8import hudson.remoting.Callable;
  9import hudson.remoting.Channel;
 10import hudson.remoting.VirtualChannel;
 11import hudson.util.Secret;
 12import org.acegisecurity.Authentication;
 13import org.acegisecurity.AuthenticationException;
 14import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
 15import org.acegisecurity.userdetails.UserDetails;
 16import org.springframework.dao.DataAccessException;
 17
 18import java.io.File;
 19import java.io.FileOutputStream;
 20import java.io.IOException;
 21import java.io.OutputStream;
 22import java.io.Serializable;
 23import java.util.Properties;
 24
 25/**
 26 * Represents the authentication credential store of the CLI client.
 27 *
 28 * <p>
 29 * This object encapsulates a remote manipulation of the credential store.
 30 * We store encrypted user names.
 31 *
 32 * @author Kohsuke Kawaguchi
 33 * @since 1.351
 34 */
 35public class ClientAuthenticationCache implements Serializable {
 36    /**
 37     * Where the store should be placed.
 38     */
 39    private final FilePath store;
 40
 41    /**
 42     * Loaded contents of the store.
 43     */
 44    private final Properties props = new Properties();
 45
 46    public ClientAuthenticationCache(Channel channel) throws IOException, InterruptedException {
 47        store = (channel==null ? MasterComputer.localChannel :  channel).call(new Callable<FilePath, IOException>() {
 48            public FilePath call() throws IOException {
 49                File home = new File(System.getProperty("user.home"));
 50                return new FilePath(new File(home, ".hudson/cli-credentials"));
 51            }
 52        });
 53        if (store.exists()) {
 54            props.load(store.read());
 55        }
 56    }
 57
 58    /**
 59     * Gets the persisted authentication for this Hudson.
 60     *
 61     * @return {@link Hudson#ANONYMOUS} if no such credential is found, or if the stored credential is invalid.
 62     */
 63    public Authentication get() {
 64        Hudson h = Hudson.getInstance();
 65        Secret userName = Secret.decrypt(props.getProperty(getPropertyKey()));
 66        if (userName==null) return Hudson.ANONYMOUS; // failed to decrypt
 67        try {
 68            UserDetails u = h.getSecurityRealm().loadUserByUsername(userName.toString());
 69            return new UsernamePasswordAuthenticationToken(u.getUsername(), u.getPassword(), u.getAuthorities());
 70        } catch (AuthenticationException e) {
 71            return Hudson.ANONYMOUS;
 72        } catch (DataAccessException e) {
 73            return Hudson.ANONYMOUS;
 74        }
 75    }
 76
 77    /**
 78     * Computes the key that identifies this Hudson among other Hudsons that the user has a credential for.
 79     */
 80    private String getPropertyKey() {
 81        String url = Hudson.getInstance().getRootUrl();
 82        if (url!=null)  return url;
 83        return Secret.fromString("key").toString();
 84    }
 85
 86    /**
 87     * Persists the specified authentication.
 88     */
 89    public void set(Authentication a) throws IOException, InterruptedException {
 90        Hudson h = Hudson.getInstance();
 91
 92        // make sure that this security realm is capable of retrieving the authentication by name,
 93        // as it's not required.
 94        UserDetails u = h.getSecurityRealm().loadUserByUsername(a.getName());
 95        props.setProperty(getPropertyKey(), Secret.fromString(u.getUsername()).getEncryptedValue());
 96
 97        save();
 98    }
 99
100    /**
101     * Removes the persisted credential, if there's one.
102     */
103    public void remove() throws IOException, InterruptedException {
104        if (props.remove(getPropertyKey())!=null)
105            save();
106    }
107
108    private void save() throws IOException, InterruptedException {
109        store.act(new FileCallable<Void>() {
110            public Void invoke(File f, VirtualChannel channel) throws IOException, InterruptedException {
111                f.getParentFile().mkdirs();
112
113                OutputStream os = new FileOutputStream(f);
114                try {
115                    props.store(os,"Credential store");
116                } finally {
117                    os.close();
118                }
119
120                // try to protect this file from other users, if we can.
121                PosixAPI.get().chmod(f.getAbsolutePath(),0600);
122                return null;
123            }
124        });
125    }
126}