1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package nl.toolforge.karma.core.vc;
20
21 import nl.toolforge.karma.core.KarmaRuntimeException;
22 import nl.toolforge.karma.core.boot.WorkingContext;
23 import nl.toolforge.karma.core.location.PasswordScrambler;
24 import org.apache.commons.digester.Digester;
25 import org.apache.commons.logging.Log;
26 import org.apache.commons.logging.LogFactory;
27 import org.xml.sax.SAXException;
28
29 import java.io.File;
30 import java.io.FileWriter;
31 import java.io.IOException;
32 import java.text.MessageFormat;
33 import java.util.ArrayList;
34 import java.util.HashMap;
35 import java.util.Hashtable;
36 import java.util.Iterator;
37 import java.util.List;
38 import java.util.Map;
39
40 /***
41 * <p>When a {@link nl.toolforge.karma.core.location.Location} - more specifically, {@link VersionControlSystem} -
42 * requires authentication, Karma provides for a mechanism whereby an d<code>authenticators.xml</code>, located in the
43 * Karma configuration directory stores a username. Depending on the specific implementation of
44 * <code>VersionControlSystem</code>, password info is then retrieved.
45 *
46 * <p>The <code>Authenticator</code> class reads the <code>authenticators.xml</code> from the Karma configuration
47 * directory and can then map <code>VersionControlSystem</code> instances by checking if an <code>authenticator</code>
48 * element is present for the location. This mapping is done by checking if the <code>id</code> attributes for the
49 * <code>location</code> and the <code>authenticator</code> are the same.
50 *
51 * @author D.A. Smedes
52 * @version $Id: Authenticators.java,v 1.6 2004/11/03 20:53:19 asmedes Exp $
53 */
54 public final class Authenticators {
55
56 private static Log logger = LogFactory.getLog(Authenticators.class);
57
58 /***
59 * Singleton, helper.
60 */
61 private Authenticators() {}
62
63 public static synchronized void changePassword(AuthenticatorKey key, String newPassword) throws AuthenticationException {
64
65 if (key == null) {
66 throw new IllegalArgumentException("Authenticator key cannot be null.");
67 }
68
69 Map authenticators = getAuthenticators();
70
71 Authenticator authenticator = ((Authenticator) authenticators.get(key));
72
73 if (authenticator == null) {
74 throw new AuthenticationException(AuthenticationException.AUTHENTICATOR_NOT_FOUND, new Object[]{key});
75 }
76
77 authenticator.setPassword(PasswordScrambler.scramble(newPassword));
78
79 try {
80 flush(authenticators);
81 } catch (IOException e) {
82 throw new AuthenticationException(e, AuthenticationException.AUTHENTICATOR_WRITE_ERROR);
83 }
84 }
85
86 public static Authenticator getAuthenticator(Authenticator authenticator) throws AuthenticationException {
87 return getAuthenticator(authenticator.getAuthenticatorKey());
88 }
89
90 /***
91 * Retrieves an <code>Authenticator</code> entry from the <code>authenticators.xml</code> file.
92 *
93 * @param key The key by which the <code>Authenticator</code> will be located.
94 * @return The <code>Authenticator</code> with key <code>key</code>.
95 * @throws AuthenticationException When no <code>Authenticator</code> can be found with key <code>key</code>.
96 */
97 public static Authenticator getAuthenticator(AuthenticatorKey key) throws AuthenticationException {
98
99 if (key == null) {
100 throw new IllegalArgumentException("Authenticator key cannot be null.");
101 }
102
103 Authenticator authenticator = ((Authenticator) getAuthenticators().get(key));
104
105 if (authenticator == null) {
106 throw new AuthenticationException(AuthenticationException.AUTHENTICATOR_NOT_FOUND, new Object[]{key});
107 }
108
109 return authenticator;
110 }
111
112 private static Map authenticatorCache = null;
113 private static long lastModified = 0l;
114
115 private synchronized static Map getAuthenticators() throws AuthenticationException {
116
117 File authenticatorsFile = new File(WorkingContext.getConfigurationBaseDir(), "authenticators.xml");
118
119 if (!authenticatorsFile.exists()) {
120 createNew();
121 }
122
123 if (authenticatorCache == null) {
124 authenticatorCache = new Hashtable();
125 logger.debug("Creating authenticator cache from `authenticators.xml`.");
126 } else {
127
128
129
130 if (authenticatorsFile.lastModified() == lastModified) {
131 logger.debug("Using authenticator cache.");
132 return authenticatorCache;
133 } else {
134 authenticatorCache = new Hashtable();
135 logger.debug("Recreating authenticator cache from `authenticators.xml`.");
136 }
137 }
138
139
140
141 Digester digester = getDigester();
142
143 List subList = null;
144 try {
145 subList = (List) digester.parse(authenticatorsFile.getPath());
146 } catch (IOException e) {
147 throw new AuthenticationException(e, AuthenticationException.MISSING_AUTHENTICATOR_CONFIGURATION);
148 } catch (SAXException e) {
149 throw new AuthenticationException(e, AuthenticationException.AUTHENTICATOR_LOAD_ERROR);
150 }
151
152 for (Iterator j = subList.iterator(); j.hasNext();) {
153 Authenticator authDescriptor = (Authenticator) j.next();
154 AuthenticatorKey key = new AuthenticatorKey(authDescriptor.getWorkingContext(), authDescriptor.getId());
155 if (authenticatorCache.containsKey(key)) {
156 throw new AuthenticationException(
157 AuthenticationException.DUPLICATE_AUTHENTICATOR_KEY,
158 new Object[] {key, WorkingContext.getConfigurationBaseDir().getPath()}
159 );
160 }
161 authenticatorCache.put(key, authDescriptor);
162 }
163
164
165
166 lastModified = authenticatorsFile.lastModified();
167
168 return authenticatorCache;
169 }
170
171 /***
172 * Adds an authenticator to <code>authenticators.xml</code> if the authenticator does not yet exist.
173 *
174 * @param authenticator
175 */
176 public static synchronized void addAuthenticator(Authenticator authenticator) throws AuthenticationException {
177
178 if (authenticator == null) {
179 throw new IllegalArgumentException("Authenticator cannot be null.");
180 }
181
182
183
184 getAuthenticators().put(authenticator.getAuthenticatorKey(), authenticator);
185
186 try {
187 flush(getAuthenticators());
188 } catch (IOException e) {
189 throw new KarmaRuntimeException(e);
190 }
191 }
192
193 /***
194 * Deletes an authenticator entry from <code>authenticators.xml</code>.
195 *
196 * @param authenticator
197 */
198 public static synchronized void deleteAuthenticator(Authenticator authenticator) throws AuthenticationException {
199
200
201
202 getAuthenticators().remove(new AuthenticatorKey(authenticator.getWorkingContext(), authenticator.getWorkingContext()));
203
204 try {
205 flush(getAuthenticators());
206 } catch (IOException e) {
207 throw new KarmaRuntimeException(e);
208 }
209 }
210
211 private static void createNew() throws AuthenticationException {
212 try {
213 flush(new HashMap());
214 } catch (IOException e) {
215 throw new AuthenticationException(e, AuthenticationException.MISSING_AUTHENTICATOR_CONFIGURATION);
216 }
217 }
218
219 private static synchronized void flush(Map authenticators) throws IOException {
220
221 StringBuffer buffer = new StringBuffer();
222
223 buffer.append("<?xml version=\"1.0\"?>\n\n");
224 buffer.append("<authenticators>\n");
225
226 for (Iterator i = authenticators.values().iterator(); i.hasNext();) {
227 MessageFormat formatter = null;
228
229 Authenticator a = (Authenticator) i.next();
230 if (a.getPassword() != null) {
231 formatter = new MessageFormat(" <authenticator working-context=\"{0}\" id=\"{1}\" username=\"{2}\" password=\"{3}\"/>\n");
232
233
234
235 String password = a.getPassword();
236 password = password.replaceAll("&", "&");
237 password = password.replaceAll("<", "<");
238 password = password.replaceAll(">", ">");
239 password = password.replaceAll("\"", """);
240 password = password.replaceAll("'", "'");
241
242 buffer.append(formatter.format(new String[]{a.getWorkingContext(), a.getId(), a.getUsername(), password}));
243 } else {
244 formatter = new MessageFormat(" <authenticator working-context=\"{0}\" id=\"{1}\" username=\"{2}\"/>\n");
245 buffer.append(formatter.format(new String[]{a.getWorkingContext(), a.getId(), a.getUsername()}));
246 }
247 }
248
249 buffer.append("</authenticators>\n");
250
251 FileWriter writer = null;
252
253
254 writer = new FileWriter(new File(WorkingContext.getConfigurationBaseDir(), "authenticators.xml"));
255 try {
256
257 writer.write(buffer.toString());
258 writer.flush();
259
260 } finally {
261 writer.close();
262 }
263 }
264
265 private static Digester getDigester() {
266
267 Digester digester = new Digester();
268
269 digester.addObjectCreate("authenticators", ArrayList.class);
270 digester.addObjectCreate("authenticators/authenticator", Authenticator.class);
271 digester.addSetProperties("authenticators/authenticator");
272 digester.addSetProperties("authenticators/authenticator", new String[]{"working-context"}, new String[]{"workingContext"});
273 digester.addSetNext("authenticators/authenticator", "add");
274 return digester;
275 }
276 }