001: /*
002: * <copyright>
003: *
004: * Copyright 2002-2004 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026:
027: package org.cougaar.core.wp.bootstrap;
028:
029: import java.io.BufferedReader;
030: import java.io.ByteArrayInputStream;
031: import java.io.InputStream;
032: import java.io.InputStreamReader;
033: import java.io.FileInputStream;
034: import java.io.ObjectInputStream;
035: import java.io.Reader;
036: import java.net.URI;
037: import java.net.URLDecoder;
038: import java.security.cert.Certificate;
039: import java.security.cert.CertificateFactory;
040: import java.util.Collections;
041: import java.util.HashMap;
042: import java.util.Map;
043: import java.util.regex.Matcher;
044: import java.util.regex.Pattern;
045: import org.cougaar.core.service.wp.AddressEntry;
046: import org.cougaar.core.service.wp.Cert;
047: import org.cougaar.core.util.UID;
048: import sun.misc.BASE64Decoder;
049:
050: /**
051: * Decode {@link Bundle}s and {@link Cert}s from encoded text.
052: *
053: * @see BundleEncoder
054: */
055: public final class BundleDecoder {
056:
057: private static final String S1 = "^\\s*" + "(\\S+)" + "=" + "(.*)"
058: + "\\s*$";
059: private static final String S2 = "^\\s*" + "([^\\s=]+)="
060: + "(\\(uri=)?" + "(\\S+)" + "(\\s+cert=(\\S+)\\s*\\))?"
061: + "\\s*" + "(,(.*)|$)";
062:
063: private static final Pattern P1 = Pattern.compile(S1);
064: private static final Pattern P2 = Pattern.compile(S2);
065:
066: private static final String BEGIN_CERT = "-----BEGIN CERTIFICATE-----\n";
067: private static final String END_CERT = "\n-----END CERTIFICATE-----";
068:
069: private BundleDecoder() {
070: }
071:
072: public static Map decodeBundles(InputStream is) throws Exception {
073: Map ret = null;
074: BufferedReader br = null;
075: try {
076: br = new BufferedReader(new InputStreamReader(is));
077: ret = decodeBundles(br);
078: } finally {
079: if (br != null) {
080: br.close();
081: }
082: }
083: return ret;
084: }
085:
086: public static Map decodeBundles(BufferedReader br) throws Exception {
087: Map ret = null;
088: try {
089: String s = null;
090: while (true) {
091: String line = br.readLine();
092: if (line == null) {
093: break;
094: }
095: if (line.startsWith("#")) {
096: continue;
097: }
098: boolean more = line.endsWith("\\");
099: if (more) {
100: line = line.substring(0, line.length() - 1);
101: }
102: if (s == null) {
103: s = line;
104: } else {
105: s += line;
106: }
107: if (more) {
108: continue;
109: }
110: Bundle b = Bundle.decode(s);
111: s = null;
112: if (b == null) {
113: continue;
114: }
115: if (ret == null) {
116: ret = new HashMap();
117: }
118: ret.put(b.getName(), b);
119: }
120: } finally {
121: if (br != null) {
122: br.close();
123: }
124: }
125: if (ret == null) {
126: ret = Collections.EMPTY_MAP;
127: }
128: return ret;
129: }
130:
131: public static Bundle decodeBundle(String s) {
132: Matcher m1 = P1.matcher(s);
133: if (!m1.matches()) {
134: throw new RuntimeException("String \"" + s
135: + "\" doesn't match pattern \"" + S1 + "\"");
136: }
137: String name = m1.group(1);
138: String suid = null;
139: String sttd = null;
140: String sentries = m1.group(2);
141: Map entries;
142: if (sentries == null || "null".equals(sentries)) {
143: entries = null;
144: } else if (!sentries.startsWith("{") || !sentries.endsWith("}")) {
145: throw new RuntimeException("Entries string \"" + sentries
146: + "\" doesn't startWith(\"{\") and endWith(\"}\"");
147: } else {
148: sentries = sentries.substring(1, sentries.length() - 1);
149: entries = new HashMap();
150: int i = 0;
151: while (true) {
152: Matcher m2 = P2.matcher(sentries.substring(i));
153: if (!m2.matches()) {
154: throw new RuntimeException("AddressEntry string["
155: + i + "] \"" + sentries.substring(i)
156: + "\" doesn't match pattern \"" + S2 + "\"");
157: }
158: String type = m2.group(1);
159: String suri = m2.group(3);
160: if ("uid".equals(type)) {
161: suid = suri;
162: } else if ("ttd".equals(type)) {
163: sttd = suri;
164: } else {
165: URI uri = URI.create(suri);
166: String scert = m2.group(5);
167: Cert cert;
168: if (scert == null) {
169: cert = Cert.NULL;
170: } else if (m2.group(2) != null) {
171: cert = decodeCert(scert);
172: } else {
173: throw new RuntimeException("Cert string \""
174: + scert + "\" not in \"cert=\""
175: + " of entries string \"" + sentries
176: + "\"");
177: }
178: AddressEntry ae = AddressEntry.getAddressEntry(
179: name, type, uri, cert);
180: entries.put(type, ae);
181: String tail = m2.group(7);
182: if (tail == null) {
183: break;
184: }
185: }
186: i += 1 + m2.start(7);
187: }
188: }
189: UID uid = (suid == null || "null".equals(suid) ? (null) : UID
190: .toUID(suid));
191: long ttd = (sttd == null || "null".equals(sttd) ? (0) : Long
192: .parseLong(sttd));
193: Bundle b = new Bundle(name, uid, ttd, entries);
194: return b;
195: }
196:
197: public static Cert decodeCert(String scert) {
198: if (scert == null || scert.equalsIgnoreCase("NULL")) {
199: return Cert.NULL;
200: }
201: if ("PROXY".equalsIgnoreCase(scert)) {
202: return Cert.PROXY;
203: }
204: int i = scert.indexOf(":");
205: if (i < 0) {
206: throw new RuntimeException("Encoded cert \"" + scert
207: + "\" lacks ':'");
208: }
209: String id = scert.substring(0, i);
210: String v = scert.substring(i + 1);
211: try {
212: if (id.equalsIgnoreCase("Indirect")) {
213: String q = URLDecoder.decode(v, "UTF-8");
214: return new Cert.Indirect(q);
215: }
216: if (id.equalsIgnoreCase("Direct")) {
217: if (!v.startsWith(BEGIN_CERT)) {
218: v = BEGIN_CERT + v;
219: }
220: if (!v.endsWith(END_CERT)) {
221: v += END_CERT;
222: }
223: byte[] ba = v.getBytes(); // specify charsetName?
224: ByteArrayInputStream is = new ByteArrayInputStream(ba);
225: String cftype = "X.509"; // make a parameter?
226: CertificateFactory cf = CertificateFactory
227: .getInstance(cftype);
228: Certificate c = cf.generateCertificate(is);
229: return new Cert.Direct(c);
230: }
231: if (id.equalsIgnoreCase("Object")) {
232: byte[] ba = (new BASE64Decoder()).decodeBuffer(v);
233: ByteArrayInputStream is = new ByteArrayInputStream(ba);
234: ObjectInputStream ois = new ObjectInputStream(is);
235: return (Cert) ois.readObject();
236: }
237: throw new RuntimeException("Unknown type: " + id);
238: } catch (Exception e) {
239: throw new RuntimeException("Unable to decodeCert(" + scert
240: + ")", e);
241: }
242: }
243:
244: public static void main(String[] args) throws Exception {
245: if (args.length != 1) {
246: System.err.println("Usage: BundleDecoder FILENAME");
247: return;
248: }
249: Map m = decodeBundles(new FileInputStream(args[0]));
250: System.out.println(args[0] + ": [" + m.size() + "]=" + m);
251: }
252: }
|