Code cleanups in preparation for 2.0 work.
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / utils / ResolverTest.java
1 /*
2  * Copyright [2005] [University Corporation for Advanced Internet Development, Inc.]
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package edu.internet2.middleware.shibboleth.utils;
18
19 import jargs.gnu.CmdLineParser;
20
21 import java.io.PrintStream;
22 import java.io.PrintWriter;
23 import java.net.MalformedURLException;
24 import java.net.URL;
25 import java.security.Principal;
26 import java.util.Collection;
27 import java.util.HashMap;
28 import java.util.Iterator;
29 import java.util.Map;
30
31 import org.apache.log4j.ConsoleAppender;
32 import org.apache.log4j.Level;
33 import org.apache.log4j.Logger;
34 import org.apache.log4j.PatternLayout;
35 import org.opensaml.SAMLException;
36 import org.w3c.dom.Document;
37 import org.w3c.dom.Element;
38 import org.w3c.dom.Node;
39 import org.w3c.dom.NodeList;
40
41 import edu.internet2.middleware.shibboleth.aa.AAAttribute;
42 import edu.internet2.middleware.shibboleth.aa.arp.ArpEngine;
43 import edu.internet2.middleware.shibboleth.aa.arp.ArpException;
44 import edu.internet2.middleware.shibboleth.aa.arp.ArpProcessingException;
45 import edu.internet2.middleware.shibboleth.aa.attrresolv.AttributeResolver;
46 import edu.internet2.middleware.shibboleth.aa.attrresolv.AttributeResolverException;
47 import edu.internet2.middleware.shibboleth.common.LocalPrincipal;
48 import edu.internet2.middleware.shibboleth.common.ShibbolethConfigurationException;
49 import edu.internet2.middleware.shibboleth.idp.IdPConfig;
50 import edu.internet2.middleware.shibboleth.idp.IdPConfigLoader;
51 import edu.internet2.middleware.shibboleth.xml.Parser;
52
53 /**
54  * Utility for testing an Attribute Resolver configuration.
55  * 
56  * @author Walter Hoehn
57  * @author Noah Levitt
58  */
59 public class ResolverTest {
60
61         private static boolean debug = false;
62         private static String resolverxml = null;
63         private static String idpXml = null;
64         private static String requester = null;
65         private static String responder = null;
66         private static String user = null;
67         private static String resource = null;
68         private static URL resourceUrl = null;
69         private static AttributeResolver resolver = null;
70         private static ArpEngine arpEngine = null;
71
72         public static void main(String[] args) {
73
74                 parseCommandLine(args);
75                 initializeResolver();
76                 Map<String, AAAttribute> attributeSet = createAttributeSet();
77                 resolveAttributes(attributeSet);
78
79                 System.out.println("Received the following from the Attribute Resolver:");
80                 System.out.println();
81                 printAttributes(System.out, attributeSet.values());
82         }
83
84         private static void resolveAttributes(Map<String, AAAttribute> attributeSet) {
85
86                 Principal principal = new LocalPrincipal(user);
87
88                 resolver.resolveAttributes(principal, requester, responder, attributeSet);
89
90                 try {
91                         if (arpEngine != null) {
92                                 arpEngine.filterAttributes(attributeSet.values(), principal, requester, resourceUrl);
93                         }
94                 } catch (ArpProcessingException e) {
95                         System.err.println("Error applying Attribute Release Policy: " + e.getMessage());
96                         System.exit(1);
97                 }
98         }
99
100         private static void parseCommandLine(String[] args) {
101
102                 CmdLineParser parser = new CmdLineParser();
103
104                 CmdLineParser.Option helpOption = parser.addBooleanOption('h', "help");
105                 CmdLineParser.Option debugOption = parser.addBooleanOption('d', "debug");
106                 CmdLineParser.Option idpXmlOption = parser.addStringOption('\u0000', "idpXml");
107                 CmdLineParser.Option userOption = parser.addStringOption('u', "user");
108                 CmdLineParser.Option requesterOption = parser.addStringOption('r', "requester");
109                 CmdLineParser.Option responderOption = parser.addStringOption('i', "responder");
110                 CmdLineParser.Option resolverxmlOption = parser.addStringOption('\u0000', "resolverxml");
111                 CmdLineParser.Option fileOption = parser.addStringOption('f', "file"); // deprecated
112                 CmdLineParser.Option resourceOption = parser.addStringOption('\u0000', "resource");
113
114                 try {
115                         parser.parse(args);
116                 } catch (CmdLineParser.OptionException e) {
117                         System.out.println(e.getMessage());
118                         printUsage(System.out);
119                         System.exit(1);
120                 }
121
122                 Boolean helpEnabled = (Boolean) parser.getOptionValue(helpOption);
123                 if (helpEnabled != null && helpEnabled.booleanValue()) {
124                         printUsage(System.out);
125                         System.exit(0);
126                 }
127
128                 Boolean debugEnabled = ((Boolean) parser.getOptionValue(debugOption));
129                 if (debugEnabled != null) {
130                         debug = debugEnabled.booleanValue();
131                 }
132
133                 // if --resolverxml and --file both specified, silently use --resolverxml
134                 resolverxml = (String) parser.getOptionValue(resolverxmlOption);
135                 if (resolverxml == null) {
136                         resolverxml = (String) parser.getOptionValue(fileOption);
137                 }
138
139                 idpXml = (String) parser.getOptionValue(idpXmlOption);
140
141                 user = (String) parser.getOptionValue(userOption);
142                 requester = (String) parser.getOptionValue(requesterOption);
143                 responder = (String) parser.getOptionValue(responderOption);
144                 resource = (String) parser.getOptionValue(resourceOption);
145
146                 configureLogging(debug);
147                 checkRequired();
148         }
149
150         /**
151          * Ensures that all required parameters were specified and successfully parsed.
152          */
153         private static void checkRequired() {
154
155                 if (user == null) {
156                         System.out.println("Missing required parameter --user.");
157                         System.out.println();
158                         printUsage(System.out);
159                         System.exit(1);
160                 }
161                 if ((resolverxml == null && idpXml == null) || (resolverxml != null && idpXml != null)) {
162                         System.out.println("Exactly one of --idpXml and --resolverxml is required.");
163                         System.out.println();
164                         printUsage(System.out);
165                         System.exit(1);
166                 }
167         }
168
169         private static Map<String, AAAttribute> createAttributeSet() {
170
171                 Collection<String> attributes = resolver.listRegisteredAttributeDefinitionPlugIns();
172                 Map<String, AAAttribute> attributeSet = new HashMap<String, AAAttribute>();
173
174                 for (String attrName : attributes) {
175                         try {
176                                 attributeSet.put(attrName, new AAAttribute(attrName));
177                         } catch (SAMLException e) {
178                                 System.err.println("Error creating AAAttribute (" + attrName + "): " + e.getMessage());
179                                 System.exit(1);
180                         }
181                 }
182
183                 return attributeSet;
184         }
185
186         private static void initializeResolver() {
187
188                 if (idpXml != null) {
189                         try {
190                                 Document idpConfig = IdPConfigLoader.getIdPConfig(idpXml);
191                                 IdPConfig configuration = new IdPConfig(idpConfig.getDocumentElement());
192
193                                 resolver = new AttributeResolver(configuration);
194
195                                 NodeList itemElements = idpConfig.getDocumentElement().getElementsByTagNameNS(
196                                                 IdPConfig.configNameSpace, "ReleasePolicyEngine");
197
198                                 if (itemElements.getLength() > 1) {
199                                         System.err
200                                                         .println("Warning: encountered multiple <ReleasePolicyEngine> configuration elements in ("
201                                                                         + idpXml + "). Using first...");
202                                 }
203
204                                 if (itemElements.getLength() < 1) {
205                                         arpEngine = new ArpEngine();
206                                 } else {
207                                         arpEngine = new ArpEngine((Element) itemElements.item(0));
208                                 }
209
210                                 if (resource != null) {
211                                         resourceUrl = new URL(resource);
212                                 }
213                         } catch (ShibbolethConfigurationException e) {
214                                 System.err.println("Error loading IdP configuration file (" + idpXml + "): " + e.getMessage());
215                                 System.exit(1);
216                         } catch (AttributeResolverException e) {
217                                 System.err.println("Error initializing the Attribute Resolver: " + e.getMessage());
218                                 System.exit(1);
219                         } catch (ArpException e) {
220                                 System.err.println("Error initializing the ARP Engine: " + e.getMessage());
221                                 System.exit(1);
222                         } catch (MalformedURLException e) {
223                                 System.err.println("Specified resource URL is invalid: " + e.getMessage());
224                                 System.exit(1);
225                         }
226                 } else {
227                         try {
228                                 resolver = new AttributeResolver(resolverxml);
229                         } catch (AttributeResolverException e) {
230                                 System.err.println("Error initializing the Attribute Resolver: " + e.getMessage());
231                                 System.exit(1);
232                         }
233                 }
234         }
235
236         private static void printAttributes(PrintStream out, Collection<AAAttribute> attributeSet) {
237
238                 try {
239                         for (Iterator<AAAttribute> iterator = attributeSet.iterator(); iterator.hasNext();) {
240                                 AAAttribute attribute = iterator.next();
241                                 Node node = attribute.toDOM();
242
243                                 if (!(node instanceof Element)) {
244                                         System.err.println("Received bad Element data from SAML library.");
245                                         System.exit(1);
246                                 }
247                                 out.println(Parser.serialize(node));
248                                 out.println();
249                         }
250                 } catch (SAMLException e) {
251                         System.err.println("Error creating SAML attribute: " + e.getMessage());
252                         System.exit(1);
253                 }
254         }
255
256         private static void configureLogging(boolean debugEnabled) {
257
258                 ConsoleAppender rootAppender = new ConsoleAppender();
259                 rootAppender.setWriter(new PrintWriter(System.out));
260                 rootAppender.setName("stdout");
261                 Logger.getRootLogger().addAppender(rootAppender);
262
263                 if (debugEnabled) {
264                         Logger.getRootLogger().setLevel(Level.DEBUG);
265                         rootAppender.setLayout(new PatternLayout("%-5p %-41X{serviceId} %d{ISO8601} (%c:%L) - %m%n"));
266                 } else {
267                         Logger.getRootLogger().setLevel(Level.INFO);
268                         Logger.getLogger("edu.internet2.middleware.shibboleth.aa.attrresolv").setLevel(Level.WARN);
269                         rootAppender.setLayout(new PatternLayout(PatternLayout.TTCC_CONVERSION_PATTERN));
270                 }
271                 Logger.getLogger("org.apache.xml.security").setLevel(Level.OFF);
272         }
273
274         private static void printUsage(PrintStream out) {
275
276                 // out.println("Tests an AA Attribute Resolver configuration.");
277                 out.println("Usage: resolvertest --user=USER {--idpXml=URL|--resolverxml=URL} [OPTION...]");
278                 out.println();
279                 out.println("Options:");
280                 out.println("  -h, --help                Print usage information");
281                 out.println("  -d, --debug               Run in debug mode");
282                 out.println("  --idpXml=FILEURL          URL of the IdP configuration file. Attributes");
283                 out.println("                              will be filtered according to the Attribute Release");
284                 out.println("                              Policy (ARP) specified in the configuration file");
285                 out.println("  --resolverxml=FILEURL     URL of the resolver configuration file. No ARP");
286                 out.println("                              filtering will be done");
287                 out.println("  --user=USER               User for whom attributes should be resolved");
288                 out.println("  --requester=REQUESTER     Name of the requester (SP). Emulates");
289                 out.println("                              unauthenticated requester if not specified");
290                 out.println("  --responder=RESPONDER     Name of the responder (IdP).");
291                 out.println("  --resource=URL            URL of the resource. Only attributes available");
292                 out.println("                              to any resource will be returned if not specified");
293         }
294 }