Add samlsign to project.
[shibboleth/cpp-opensaml.git] / samlsign / samlsign.cpp
1 /*\r
2  *  Copyright 2001-2007 Internet2\r
3  * \r
4  * Licensed under the Apache License, Version 2.0 (the "License");\r
5  * you may not use this file except in compliance with the License.\r
6  * You may obtain a copy of the License at\r
7  *\r
8  *     http://www.apache.org/licenses/LICENSE-2.0\r
9  *\r
10  * Unless required by applicable law or agreed to in writing, software\r
11  * distributed under the License is distributed on an "AS IS" BASIS,\r
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
13  * See the License for the specific language governing permissions and\r
14  * limitations under the License.\r
15  */\r
16 \r
17 /* siterefresh.cpp - command-line tool to refresh and verify metadata\r
18 \r
19    Scott Cantor\r
20    5/12/03\r
21 \r
22    $Id:siterefresh.cpp 2252 2007-05-20 20:20:57Z cantor $\r
23 */\r
24 \r
25 #if defined (_MSC_VER) || defined(__BORLANDC__)\r
26 # include "config_win32.h"\r
27 #else\r
28 # include "config.h"\r
29 #endif\r
30 \r
31 #ifdef WIN32\r
32 # define _CRT_NONSTDC_NO_DEPRECATE 1\r
33 # define _CRT_SECURE_NO_DEPRECATE 1\r
34 #endif\r
35 \r
36 #include <saml/SAMLConfig.h>\r
37 #include <saml/saml2/metadata/Metadata.h>\r
38 #include <saml/util/SAMLConstants.h>\r
39 #include <xmltooling/logging.h>\r
40 #include <xmltooling/XMLToolingConfig.h>\r
41 #include <xmltooling/signature/Signature.h>\r
42 #include <xmltooling/util/XMLHelper.h>\r
43 \r
44 #include <fstream>\r
45 #include <xercesc/framework/LocalFileInputSource.hpp>\r
46 #include <xercesc/framework/URLInputSource.hpp>\r
47 #include <xercesc/framework/StdInInputSource.hpp>\r
48 #include <xercesc/framework/Wrapper4InputSource.hpp>\r
49 \r
50 using namespace xmlsignature;\r
51 using namespace xmlconstants;\r
52 using namespace xmltooling::logging;\r
53 using namespace xmltooling;\r
54 using namespace samlconstants;\r
55 using namespace opensaml::saml2md;\r
56 using namespace opensaml;\r
57 using namespace xercesc;\r
58 using namespace std;\r
59 \r
60 template<class T> T* buildPlugin(const char* path, PluginManager<T,string,const DOMElement*>& mgr)\r
61 {\r
62     ifstream in(path);
63     DOMDocument* doc=XMLToolingConfig::getConfig().getParser().parse(in);
64     XercesJanitor<DOMDocument> janitor(doc);
65     
66     static const XMLCh _type[] = UNICODE_LITERAL_4(t,y,p,e);
67     auto_ptr_char type(doc->getDocumentElement()->getAttributeNS(NULL,_type));
68     if (type.get() && *type.get())
69         return mgr.newPlugin(type.get(), doc->getDocumentElement());
70     throw XMLToolingException("Missing type in plugin configuration.");
71 }\r
72 \r
73 CredentialResolver* buildSimpleResolver(const char* key, const char* cert)\r
74 {\r
75     static const XMLCh _CredentialResolver[] =  UNICODE_LITERAL_18(C,r,e,d,e,n,t,i,a,l,R,e,s,o,l,v,e,r);\r
76     static const XMLCh _certificate[] =     UNICODE_LITERAL_11(c,e,r,t,i,f,i,c,a,t,e);\r
77     static const XMLCh _key[] =             UNICODE_LITERAL_3(k,e,y);\r
78 \r
79     DOMDocument* doc = XMLToolingConfig::getConfig().getParser().newDocument();\r
80     XercesJanitor<DOMDocument> janitor(doc);\r
81     DOMElement* root = doc->createElementNS(NULL, _CredentialResolver);\r
82     if (key) {\r
83         auto_ptr_XMLCh widenit(key);\r
84         root->setAttributeNS(NULL, _key, widenit.get());\r
85     }\r
86     if (cert) {\r
87         auto_ptr_XMLCh widenit(cert);\r
88         root->setAttributeNS(NULL, _certificate, widenit.get());\r
89     }\r
90 \r
91     return XMLToolingConfig::getConfig().CredentialResolverManager.newPlugin(FILESYSTEM_CREDENTIAL_RESOLVER, root);\r
92 }\r
93 \r
94 int main(int argc,char* argv[])\r
95 {\r
96     bool verify=true;\r
97     char* url_param=NULL;\r
98     char* path_param=NULL;\r
99     char* key_param=NULL;\r
100     char* cert_param=NULL;\r
101     char* cr_param=NULL;\r
102     char* t_param=NULL;\r
103     char* id_param=NULL;\r
104 \r
105     // metadata lookup options\r
106     char* m_param=NULL;\r
107     char* issuer=NULL;\r
108     char* prot = NULL;\r
109     const XMLCh* protocol = NULL;\r
110     char* rname = NULL;\r
111     char* rns = NULL;\r
112 \r
113     for (int i=1; i<argc; i++) {\r
114         if (!strcmp(argv[i],"-u") && i+1<argc)\r
115             url_param=argv[++i];\r
116         else if (!strcmp(argv[i],"-f") && i+1<argc)\r
117             path_param=argv[++i];\r
118         else if (!strcmp(argv[i],"-id") && i+1<argc)\r
119             id_param=argv[++i];\r
120         else if (!strcmp(argv[i],"-s"))\r
121             verify=false;\r
122         else if (!strcmp(argv[i],"-k") && i+1<argc)\r
123             key_param=argv[++i];\r
124         else if (!strcmp(argv[i],"-c") && i+1<argc)\r
125             cert_param=argv[++i];\r
126         else if (!strcmp(argv[i],"-R") && i+1<argc)\r
127             cr_param=argv[++i];\r
128         else if (!strcmp(argv[i],"-T") && i+1<argc)\r
129             t_param=argv[++i];\r
130         else if (!strcmp(argv[i],"-M") && i+1<argc)\r
131             m_param=argv[++i];\r
132         else if (!strcmp(argv[i],"-i") && i+1<argc)\r
133             issuer=argv[++i];\r
134         else if (!strcmp(argv[i],"-p") && i+1<argc)\r
135             prot=argv[++i];\r
136         else if (!strcmp(argv[i],"-r") && i+1<argc)\r
137             rname=argv[++i];\r
138         else if (!strcmp(argv[i],"-ns") && i+1<argc)\r
139             rns=argv[++i];\r
140         else if (!strcmp(argv[i],"-saml10"))\r
141             protocol=samlconstants::SAML10_PROTOCOL_ENUM;\r
142         else if (!strcmp(argv[i],"-saml11"))\r
143             protocol=samlconstants::SAML11_PROTOCOL_ENUM;\r
144         else if (!strcmp(argv[i],"-saml2"))\r
145             protocol=samlconstants::SAML20P_NS;\r
146         else if (!strcmp(argv[i],"-idp"))\r
147             rname="IDPSSODescriptor";\r
148         else if (!strcmp(argv[i],"-aa"))\r
149             rname="AttributeAuthorityDescriptor";\r
150         else if (!strcmp(argv[i],"-pdp"))\r
151             rname="PDPDescriptor";\r
152         else if (!strcmp(argv[i],"-sp"))\r
153             rname="SPSSODescriptor";\r
154     }\r
155 \r
156     if (!verify && !key_param && !cr_param) {\r
157         cerr << "either -k or -R option required when signing, see documentation for usage" << endl;\r
158         return -1;\r
159     }\r
160 \r
161     SAMLConfig& conf=SAMLConfig::getConfig();\r
162     if (!conf.init())\r
163         return -2;\r
164     XMLToolingConfig& xmlconf = XMLToolingConfig::getConfig();\r
165     Category& log = Category::getInstance("OpenSAML.Utility.SAMLSign");\r
166 \r
167     int ret = 0;\r
168 \r
169     try {\r
170         // Parse the specified document.\r
171         static XMLCh base[]={chLatin_f, chLatin_i, chLatin_l, chLatin_e, chColon, chForwardSlash, chForwardSlash, chForwardSlash, chNull};\r
172         DOMDocument* doc=NULL;\r
173         if (url_param) {\r
174             URLInputSource src(base,url_param);\r
175             Wrapper4InputSource dsrc(&src,false);\r
176             doc=xmlconf.getParser().parse(dsrc);\r
177         }\r
178         else if (path_param) {\r
179             auto_ptr_XMLCh widenit(path_param);\r
180             LocalFileInputSource src(base,widenit.get());\r
181             Wrapper4InputSource dsrc(&src,false);\r
182             doc=xmlconf.getParser().parse(dsrc);\r
183         }\r
184         else {\r
185             StdInInputSource src;\r
186             Wrapper4InputSource dsrc(&src,false);\r
187             doc=xmlconf.getParser().parse(dsrc);\r
188         }\r
189     \r
190         // Unmarshall it.\r
191         XercesJanitor<DOMDocument> jan(doc);\r
192         auto_ptr<XMLObject> sourcewrapper(XMLObjectBuilder::buildOneFromElement(doc->getDocumentElement(), true));\r
193         jan.release();\r
194 \r
195         // Navigate to the selected node, or use the root if no ID specified.\r
196         // Then make sure it's a SignableSAMLObject.\r
197         XMLObject* source = sourcewrapper.get();\r
198         if (id_param) {\r
199             auto_ptr_XMLCh widenit(id_param);\r
200             source = XMLHelper::getXMLObjectById(*source, widenit.get());\r
201             if (!source)\r
202                 throw XMLToolingException("Element with ID ($1) not found.", params(1,id_param));\r
203         }\r
204         SignableObject* signable = dynamic_cast<SignableObject*>(source);\r
205         if (!signable)\r
206             throw XMLToolingException("Input is not a signable SAML object.");\r
207 \r
208         if (verify) {\r
209         }\r
210         else {\r
211             // Build a resolver to supply a credential.\r
212             auto_ptr<CredentialResolver> cr(\r
213                 cr_param ? buildPlugin(cr_param, xmlconf.CredentialResolverManager) : buildSimpleResolver(key_param, cert_param)\r
214                 );\r
215             cr->lock();\r
216             CredentialCriteria cc;\r
217             cc.setUsage(CredentialCriteria::SIGNING_CREDENTIAL);\r
218             const Credential* cred = cr->resolve(&cc);\r
219             if (!cred)\r
220                 throw XMLSecurityException("Unable to resolve a signing credential.");\r
221 \r
222             // Attach new signature.\r
223             Signature* sig = SignatureBuilder::buildSignature();
224             signable->setSignature(sig);
225
226             // Sign response while re-marshalling.
227             vector<Signature*> sigs(1,sig);
228             XMLHelper::serialize(signable->marshall((DOMDocument*)NULL,&sigs,cred), cout);
229         }\r
230     }\r
231     catch(exception& e) {\r
232         log.errorStream() << "caught an exception: " << e.what() << CategoryStream::ENDLINE;\r
233         ret=-10;\r
234     }\r
235     catch(XMLException& e) {\r
236         auto_ptr_char temp(e.getMessage());\r
237         log.errorStream() << "caught a Xerces exception: " << temp.get() << CategoryStream::ENDLINE;\r
238         ret=-20;\r
239     }\r
240 \r
241     conf.term();\r
242     return ret;\r
243 }\r