001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018:
019: package org.apache.jmeter.protocol.http.control;
020:
021: import java.io.BufferedReader;
022: import java.io.File;
023: import java.io.FileReader;
024: import java.io.FileWriter;
025: import java.io.IOException;
026: import java.io.PrintWriter;
027: import java.io.Serializable;
028: import java.net.MalformedURLException;
029: import java.net.URL;
030: import java.util.ArrayList;
031: import java.util.Collection;
032: import java.util.NoSuchElementException;
033: import java.util.StringTokenizer;
034:
035: import org.apache.jmeter.config.ConfigElement;
036: import org.apache.jmeter.config.ConfigTestElement;
037: import org.apache.jmeter.testelement.TestElement;
038: import org.apache.jmeter.testelement.property.CollectionProperty;
039: import org.apache.jmeter.testelement.property.PropertyIterator;
040: import org.apache.jmeter.testelement.property.TestElementProperty;
041: import org.apache.jmeter.util.JMeterUtils;
042: import org.apache.jorphan.logging.LoggingManager;
043: import org.apache.log.Logger;
044:
045: // For Unit tests, @see TestAuthManager
046:
047: /**
048: * This class provides a way to provide Authorization in jmeter requests. The
049: * format of the authorization file is: URL user pass where URL is an HTTP URL,
050: * user a username to use and pass the appropriate password.
051: *
052: * author <a href="mailto:luta.raphael@networks.vivendi.com">Raphael Luta</a>
053: */
054: public class AuthManager extends ConfigTestElement implements
055: ConfigElement, Serializable {
056: private static final Logger log = LoggingManager
057: .getLoggerForClass();
058:
059: private final static String AUTH_LIST = "AuthManager.auth_list"; //$NON-NLS-1$
060:
061: private final static String[] columnNames = {
062: JMeterUtils.getResString("auth_base_url"), //$NON-NLS-1$
063: JMeterUtils.getResString("username"), //$NON-NLS-1$
064: JMeterUtils.getResString("password"), //$NON-NLS-1$
065: JMeterUtils.getResString("domain"), //$NON-NLS-1$
066: JMeterUtils.getResString("realm"), //$NON-NLS-1$
067: };
068:
069: // Column numbers - must agree with order above
070: public final static int COL_URL = 0;
071: public final static int COL_USERNAME = 1;
072: public final static int COL_PASSWORD = 2;
073: public final static int COL_DOMAIN = 3;
074: public final static int COL_REALM = 4;
075:
076: private final static int columnCount = columnNames.length;
077:
078: /**
079: * Default Constructor.
080: */
081: public AuthManager() {
082: setProperty(new CollectionProperty(AUTH_LIST, new ArrayList()));
083: }
084:
085: public void clear() {
086: super .clear();
087: setProperty(new CollectionProperty(AUTH_LIST, new ArrayList()));
088: }
089:
090: /**
091: * Update an authentication record.
092: */
093: public void set(int index, String url, String user, String pass,
094: String domain, String realm) {
095: Authorization auth = new Authorization(url, user, pass, domain,
096: realm);
097: if (index >= 0) {
098: getAuthObjects().set(index,
099: new TestElementProperty(auth.getName(), auth));
100: } else {
101: getAuthObjects().addItem(auth);
102: }
103: }
104:
105: public void setName(String newName) {
106: setProperty(TestElement.NAME, newName);
107: }
108:
109: public CollectionProperty getAuthObjects() {
110: return (CollectionProperty) getProperty(AUTH_LIST);
111: }
112:
113: public int getColumnCount() {
114: return columnCount;
115: }
116:
117: public String getColumnName(int column) {
118: return columnNames[column];
119: }
120:
121: public Class getColumnClass(int column) {
122: return columnNames[column].getClass();
123: }
124:
125: public Authorization getAuthObjectAt(int row) {
126: return (Authorization) getAuthObjects().get(row)
127: .getObjectValue();
128: }
129:
130: public boolean isEditable() {
131: return true;
132: }
133:
134: public String getClassLabel() {
135: return JMeterUtils.getResString("auth_manager_title"); //$NON-NLS-1$
136: }
137:
138: public Class getGuiClass() {
139: return org.apache.jmeter.protocol.http.gui.AuthPanel.class;
140: }
141:
142: public Collection getAddList() {
143: return null;
144: }
145:
146: /**
147: * Return the record at index i
148: */
149: public Authorization get(int i) {
150: return (Authorization) getAuthObjects().get(i).getObjectValue();
151: }
152:
153: public String getAuthHeaderForURL(URL url) {
154: Authorization auth = getAuthForURL(url);
155: if (auth == null)
156: return null;
157: return auth.toBasicHeader();
158: }
159:
160: public Authorization getAuthForURL(URL url) {
161: if (!isSupportedProtocol(url)) {
162: return null;
163: }
164:
165: // TODO: replace all this url2 mess with a proper method
166: // "areEquivalent(url1, url2)" that
167: // would also ignore case in protocol and host names, etc. -- use that
168: // method in the CookieManager too.
169:
170: URL url2 = null;
171:
172: try {
173: if (url.getPort() == -1) {
174: // Obtain another URL with an explicit port:
175: int port = url.getProtocol().equalsIgnoreCase("http") ? 80
176: : 443;
177: // only http and https are supported
178: url2 = new URL(url.getProtocol(), url.getHost(), port,
179: url.getPath());
180: } else if ((url.getPort() == 80 && url.getProtocol()
181: .equalsIgnoreCase("http"))
182: || (url.getPort() == 443 && url.getProtocol()
183: .equalsIgnoreCase("https"))) {
184: url2 = new URL(url.getProtocol(), url.getHost(), url
185: .getPath());
186: }
187: } catch (MalformedURLException e) {
188: log.error("Internal error!", e); // this should never happen
189: // anyway, we'll continue with url2 set to null.
190: }
191:
192: String s1 = url.toString();
193: String s2 = null;
194: if (url2 != null)
195: s2 = url2.toString();
196:
197: log.debug("Target URL strings to match against: " + s1
198: + " and " + s2);
199: // TODO should really return most specific (i.e. longest) match.
200: for (PropertyIterator iter = getAuthObjects().iterator(); iter
201: .hasNext();) {
202: Authorization auth = (Authorization) iter.next()
203: .getObjectValue();
204:
205: String uRL = auth.getURL();
206: log.debug("Checking match against auth'n entry: " + uRL);
207: if (s1.startsWith(uRL) || s2 != null && s2.startsWith(uRL)) {
208: log.debug("Matched");
209: return auth;
210: }
211: log.debug("Did not match");
212: }
213: return null;
214: }
215:
216: public String getName() {
217: return getPropertyAsString(TestElement.NAME);
218: }
219:
220: public void addConfigElement(ConfigElement config) {
221: }
222:
223: public void addAuth(Authorization auth) {
224: getAuthObjects().addItem(auth);
225: }
226:
227: public void addAuth() {
228: getAuthObjects().addItem(new Authorization());
229: }
230:
231: public boolean expectsModification() {
232: return false;
233: }
234:
235: public void uncompile() {// TODO is this used?
236: }
237:
238: /**
239: * Save the authentication data to a file.
240: */
241: public void save(String authFile) throws IOException {
242: File file = new File(authFile);
243: if (!file.isAbsolute()) {
244: file = new File(System.getProperty("user.dir"), authFile);
245: }
246: PrintWriter writer = new PrintWriter(new FileWriter(file));
247: writer.println("# JMeter generated Authorization file");
248: for (int i = 0; i < getAuthObjects().size(); i++) {
249: Authorization auth = (Authorization) getAuthObjects()
250: .get(i).getObjectValue();
251: writer.println(auth.toString());
252: }
253: writer.flush();
254: writer.close();
255: }
256:
257: /**
258: * Add authentication data from a file.
259: */
260: public void addFile(String authFile) throws IOException {
261: File file = new File(authFile);
262: if (!file.isAbsolute()) {
263: file = new File(System.getProperty("user.dir")
264: + File.separator + authFile);
265: }
266: BufferedReader reader = null;
267: if (file.canRead()) {
268: reader = new BufferedReader(new FileReader(file));
269: } else {
270: throw new IOException(
271: "The file you specified cannot be read.");
272: }
273:
274: String line;
275: boolean ok = true;
276: while ((line = reader.readLine()) != null) {
277: try {
278: if (line.startsWith("#") || line.trim().length() == 0) { //$NON-NLS-1$
279: continue;
280: }
281: StringTokenizer st = new StringTokenizer(line, "\t"); //$NON-NLS-1$
282: String url = st.nextToken();
283: String user = st.nextToken();
284: String pass = st.nextToken();
285: String domain = "";
286: String realm = "";
287: if (st.hasMoreTokens()) {// Allow for old format file without the extra columnns
288: domain = st.nextToken();
289: realm = st.nextToken();
290: }
291: Authorization auth = new Authorization(url, user, pass,
292: domain, realm);
293: getAuthObjects().addItem(auth);
294: } catch (NoSuchElementException e) {
295: log.error("Error parsing auth line: '" + line + "'");
296: ok = false;
297: }
298: }
299: reader.close();
300: if (!ok) {
301: JMeterUtils
302: .reportErrorToUser("One or more errors found when reading the Auth file - see the log file");
303: }
304: }
305:
306: /**
307: * Remove an authentication record.
308: */
309: public void remove(int index) {
310: getAuthObjects().remove(index);
311: }
312:
313: /**
314: * Return the number of records.
315: */
316: public int getAuthCount() {
317: return getAuthObjects().size();
318: }
319:
320: // Needs to be package protected for Unit test
321: static boolean isSupportedProtocol(URL url) {
322: String protocol = url.getProtocol().toUpperCase();
323: return protocol.equals("HTTP") || protocol.equals("HTTPS"); //$NON-NLS-1$ //$NON-NLS-2$
324: }
325: }
|