View Javadoc

1   /*
2    * Copyright 2010 Fraunhofer Gesellschaft, Munich, Germany,
3    * for its Fraunhofer Institute for Computer Architecture and Software
4    * Technology (FIRST), Berlin, Germany. All rights reserved.
5    * http://www.first.fraunhofer.de/
6    */
7   
8   package net.kwfgrid.gwes;
9   
10  import net.kwfgrid.gwes.util.StringUtils;
11  import net.kwfgrid.gwes.exception.LoggingException;
12  import net.kwfgrid.gwes.exception.WorkflowSecurityException;
13  import org.apache.log4j.Logger;
14  import org.globus.common.CoGProperties;
15  import org.gridforum.jgss.ExtendedGSSCredential;
16  import org.gridforum.jgss.ExtendedGSSManager;
17  import org.ietf.jgss.GSSCredential;
18  import org.ietf.jgss.GSSException;
19  
20  import java.io.File;
21  import java.io.FileInputStream;
22  import java.io.IOException;
23  
24  /**
25   * Credential manager for secured activities.
26   *
27   * @author Andreas Hoheisel
28   *         (<a href="http://www.andreas-hoheisel.de">www.andreas-hoheisel.de</a>)
29   * @version $Id: CredentialManager.java 1532 2011-06-23 15:57:53Z hoheisel $
30   */
31  public class CredentialManager {
32  
33      static final Logger logger = Logger.getLogger(CredentialManager.class);
34  
35      /**
36       * minimum remaining credential lifetime in seconds.
37       */
38      final private static int MIN_REMAINING_LIFETIME = 60*60;
39  
40      private GSSCredential credential;
41  
42      private File proxyFile;
43  
44      /**
45       * The mode specifies the retrieval method for credentials.
46       */
47      private int mode;
48  
49      /**
50       * Use the default Globus credential.
51       */
52      public final static int MODE_DEFAULT_PROXY_FILE = 1;
53  
54      /**
55       * Use a secific proxy file.
56       */
57      public final static int MODE_PROXY_FILE = 2;
58  
59      /**
60       * Use a specific credential.
61       */
62      public final static int MODE_USER_CREDENTIAL = 4;
63  
64      /**
65       * Create credential manager which uses default Globus Toolkit credential as defined in cog.properties
66       * (property X509_USER_PROXY).
67       */
68      public CredentialManager() throws GSSException, IOException, LoggingException {
69          String dn = null;
70          Throwable error = null;
71          try {
72              this.mode = MODE_DEFAULT_PROXY_FILE;
73              this.credential = getDefaultCredential();
74              dn = getDN();
75          } catch (GSSException e) {
76              error = e; throw e;
77          } catch (IOException e) {
78              error = e; throw e;
79          } catch (Throwable e) {
80              error = e; throw new IOException(e.toString(),e);
81          } finally {
82              if (error == null) { // SUCCESS
83                  GWESLogger.getInstance().logEventSP(GWESLogger.Event.LOAD_CREDENTIAL,dn,this,"defaultGlobusProxyFile",null,proxyFile.getAbsolutePath());
84              } else {             // ERROR
85                  GWESLogger.getInstance().logEventSP(GWESLogger.Event.LOAD_CREDENTIAL,GWESLogger.EventOutcome.ERROR,dn,this,"defaultGlobusProxyFile",null,proxyFile.getAbsolutePath(),error);
86              }
87          }
88      }
89  
90      /**
91       * Create credential manager which uses specific proxy File.
92       * @param proxyFile
93       */
94      public CredentialManager(File proxyFile) throws GSSException, IOException, LoggingException {
95          String dn = null;
96          Throwable error = null;
97          try {
98              this.mode = MODE_PROXY_FILE;
99              this.proxyFile = proxyFile;
100             this.credential = getCredentialFromProxyFile();
101             dn = getDN();
102         } catch (GSSException e) {
103             error = e; throw e;
104         } catch (IOException e) {
105             error = e; throw e;
106         } catch (Throwable e) {
107             error = e; throw new IOException(e.toString(),e);
108         } finally {
109             if (error == null) { // SUCCESS
110                 GWESLogger.getInstance().logEventSP(GWESLogger.Event.LOAD_CREDENTIAL,dn,this,"proxyFile",null,proxyFile.getAbsolutePath());
111             } else {             // ERROR
112                 GWESLogger.getInstance().logEventSP(GWESLogger.Event.LOAD_CREDENTIAL,GWESLogger.EventOutcome.ERROR,dn,this,"proxyFile",null,proxyFile.getAbsolutePath(),error);
113             }
114         }
115     }
116 
117     /**
118      * Create credential manager which uses specific GSSCredential.
119      * @param credential
120      */
121     public CredentialManager(GSSCredential credential) throws LoggingException, GSSException {
122         String dn = null;
123         Throwable error = null;
124         try {
125             this.mode = MODE_USER_CREDENTIAL;
126             this.credential = credential;
127             dn = getDN();
128         } catch (GSSException e) {
129             error = e; throw e;
130         } finally {
131             if (error == null) { // SUCCESS
132                 GWESLogger.getInstance().logEvent(GWESLogger.Event.LOAD_CREDENTIAL,dn,this);
133             } else {             // ERROR
134                 GWESLogger.getInstance().logEvent(GWESLogger.Event.LOAD_CREDENTIAL,GWESLogger.EventOutcome.ERROR,dn,this,error);
135             }
136         }
137     }
138 
139     /**
140      * Create credential manager which uses specific userID|credential string.
141      * @param userIdCredential
142      */
143     public CredentialManager(String userIdCredential) throws GSSException, LoggingException {
144         String dn = null;
145         Throwable error = null;
146         try {
147             this.mode = MODE_USER_CREDENTIAL;
148             this.credential = getGSSCredential(extractCredential(userIdCredential));
149             dn = getDN();
150         } catch (GSSException e) {
151             error = e; throw e;
152         } finally {
153             if (error == null) { // SUCCESS
154                 GWESLogger.getInstance().logEvent(GWESLogger.Event.LOAD_CREDENTIAL,dn,this);
155             } else {             // ERROR
156                 GWESLogger.getInstance().logEvent(GWESLogger.Event.LOAD_CREDENTIAL,GWESLogger.EventOutcome.ERROR,dn,this,error);
157             }
158         }
159     }
160 
161     public GSSCredential getCredential() throws GSSException, IOException {
162         switch(mode) {
163             case MODE_DEFAULT_PROXY_FILE:
164             case MODE_PROXY_FILE:
165                 //try to reload credential from proxy if lifetime is less than MIN_REMAINING_LIFETIME
166                 if (credential.getRemainingLifetime() < MIN_REMAINING_LIFETIME) {
167                     logger.warn("remaining credential lifetime for credential \""+getDN()+"\" not sufficient - reloading credential...");
168                     credential = getCredentialFromProxyFile();
169                 }
170             case MODE_USER_CREDENTIAL:
171                 //nothing to do
172         }
173         return credential;
174     }
175 
176     public void setCredential(String credentialString) throws GSSException, LoggingException {
177             setCredential(getGSSCredential(credentialString));
178     }
179 
180     public void setCredential(GSSCredential credential) throws GSSException, LoggingException {
181         String dn = null;
182         Throwable error = null;
183         String oldDN = null;
184         try {
185             if (mode != MODE_USER_CREDENTIAL) throw new GSSException(GSSException.UNAUTHORIZED);
186             oldDN = getDN();
187             this.credential = credential;
188             dn = getDN();
189         } catch (GSSException e) {
190             error = e; throw e;
191         } finally {
192             if (error == null) { // SUCCESS
193                 GWESLogger.getInstance().logEventSP(GWESLogger.Event.SET_CREDENTIAL,dn,this,"DN",oldDN,dn);
194             } else {             // ERROR
195                 GWESLogger.getInstance().logEventSP(GWESLogger.Event.SET_CREDENTIAL,GWESLogger.EventOutcome.ERROR,dn,this,"DN",oldDN,dn,error);
196             }
197         }
198     }
199 
200     public String getDN() throws GSSException {
201         if (credential == null) throw new GSSException(GSSException.NO_CRED);
202         return credential.getName().toString();
203     }
204     
205     public String getFilteredCN() throws GSSException {
206         return StringUtils.extractFilteredCNFromDN(getDN());
207     }
208 
209     /**
210      * Create a GSSCredential from a proxy file generated with grid-proxy-init.
211      *
212      * @throws IOException
213      * @throws GSSException
214      */
215     private GSSCredential getCredentialFromProxyFile() throws IOException, GSSException {
216         if (proxyFile == null) throw new IOException("proxy file not defined");
217         if (logger.isDebugEnabled()) {
218             logger.debug("loading credential from file " + proxyFile.getAbsolutePath() + " ...");
219         }
220         byte[] proxyData = new byte[(int) proxyFile.length()];
221         FileInputStream inputStream = new FileInputStream(proxyFile);
222         inputStream.read(proxyData);
223         inputStream.close();
224 
225         ExtendedGSSManager manager =
226                 (ExtendedGSSManager) ExtendedGSSManager.getInstance();
227 
228         GSSCredential ret = manager.createCredential(proxyData, ExtendedGSSCredential.IMPEXP_OPAQUE, GSSCredential.DEFAULT_LIFETIME,
229                 null, GSSCredential.INITIATE_AND_ACCEPT);
230         if (ret == null) throw new GSSException(GSSException.NO_CRED);
231         return ret;
232     }
233 
234     /**
235      * Load default globus credential.
236      * <p/>
237      * It first checks the X509_USER_PROXY system property. If the property
238      * is not set, it checks next the 'proxy' property in the current
239      * configuration. If that property is not set, then it defaults to a
240      * value based on the following rules: <BR>
241      * If a UID system property is set, and running on a Unix machine it
242      * returns /tmp/x509up_u${UID}. If any other machine then Unix, it returns
243      * ${tempdir}/x509up_u${UID}, where tempdir is a platform-specific
244      * temporary directory as indicated by the java.io.tmpdir system property.
245      * If a UID system property is not set, the username will be used instead
246      * of the UID. That is, it returns ${tempdir}/x509up_u_${username}
247      * <BR>
248      * This is done this way because Java is not able to obtain the current
249      * uid.
250      *
251      * @throws GSSException
252      * @throws IOException
253      */
254     private GSSCredential getDefaultCredential() throws GSSException, IOException {
255         logger.debug("loading default credential ...");
256         proxyFile = new File(CoGProperties.getDefault().getProxyFile());
257         return getCredentialFromProxyFile();
258     }
259 
260     /**
261      * Extract a credential from a userIdCredential. The format is "userID|credentialString".
262      * @param userIdCredential The format is "userID|credentialString".
263      * @return the credentialString.
264      */
265     public static String extractCredential(String userIdCredential) {
266         if (userIdCredential == null) return null;
267         String ret = null;
268         // Extract credential from userID string
269         int idelim = userIdCredential.indexOf('|');
270         if (idelim > 0 && userIdCredential.length() > idelim + 1) {
271             ret = userIdCredential.substring(idelim + 1);
272         }
273         return ret;
274     }
275 
276     /**
277      * Get userID from userIdCredential String.
278      * @param userIdCredential The format is "userID|credentialString".
279      * @return If userIdCredential contains a credential, then this method returns the DN of the credential. If not,
280      * this method just returns the userID (part before "|").
281      */
282     public static String extractUserId(String userIdCredential) throws LoggingException, WorkflowSecurityException {
283         if (userIdCredential == null) return null;
284         if (extractCredential(userIdCredential)==null) {
285             // there is no credential -> just return userID
286             int idelim = userIdCredential.indexOf('|');
287             if (idelim > -1) {
288                 return userIdCredential.substring(0,idelim);
289             } else {
290                 return userIdCredential;
291             }
292         }
293         // check for credential and return DN.
294         String dn = null;
295         try {
296             CredentialManager c = new CredentialManager(userIdCredential);
297             dn = c.getDN();
298         } catch (GSSException e) {
299             throw new WorkflowSecurityException("Exception when extracting userID from credential:" + e.toString(),e);
300         }
301         return dn;
302     }
303 
304     /**
305      * Convert a credential String to a GSSCredential.
306      * @param credentialString
307      * @return
308      * @throws GSSException
309      */
310     public static GSSCredential getGSSCredential(String credentialString) throws GSSException {
311         GSSCredential ret = null;
312         if ((credentialString != null && credentialString.length() != 0)) {
313             ret = ((ExtendedGSSManager) ExtendedGSSManager.getInstance())
314                     .createCredential(credentialString.replaceAll("NEWLINE", "\n").getBytes(),
315                             ExtendedGSSCredential.IMPEXP_OPAQUE,
316                             GSSCredential.DEFAULT_LIFETIME, null,
317                             GSSCredential.INITIATE_AND_ACCEPT);
318         }
319         if (ret == null) throw new GSSException(GSSException.NO_CRED);
320         return ret;
321     }
322 
323 }