/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

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