UNPKG

12.3 kBMarkdownView Raw
1## SAML delegation
2
3Some advanced SAML use cases involve a single logical transaction that spans one or more intermediate
4clients or servers. A common example includes a SAML-enabled web site acting on behalf of a logged-in
5user while accessing additional SAML-enabled services, which are not directly accessible
6by the user agent, e.g. a database. Generalizing this example, a number of intermediaries might be
7traversed before the final point of access. Popular ways of making this happen are
8__SAML impersonation__, __SAML assertion forwarding__ and __SAML IdP proxy__.
9
10All of them suck:
11
12* SAML impersonation forces principal to disclose credentials to an SP.
13* SAML forwarding makes IdP lose track of who and when is using forwarded assertions.
14* IdP proxy requires a second IdP in exotic configuration.
15
16When a SAML assertion is used as a security token to authenticate/authorize people and software
17against a mission-critical service, it is important that the identities and order of intermediaries,
18if any, are expressed within the token in some fashion.
19
20__SAML assertion delegation__ moves beyond the forwarding scenario by adding information to the
21assertion that explicitly identifies the chain of parties through which a transaction flows.
22Delegation assures that all requests in the chain are routed back through the identity provider at
23each hop to cryptographically guarantee that each party has been authenticated and appropriate
24policy enforced. This finegrained and real-time enforcement capability is a key advantage over
25pure SAML forwarding and impersonation, at a price of additional back-channel operation for
26each delegation hop.
27
28[__Shibboleth Identity Provider__]() implements SAML 2.0 profile for assertion delegation (Liberty/IDWSF).
29
30__hana-saml-wsse__ is the corresponding client. It also implements an __ECP__ client, which is handy
31for testing your delegation configuration, but can be very useful in its own right, e.g.
32if you are implementing impersonation or fowarding model.
33
34The package name is historical; the client has been originally implemented for a specific use case
35that involved a SAP HANA database backend. Making Shibboleth delegation work with SAP HANA requires
36additional IdP configuration, which is not covered here.
37
38## Compatibility
39
40This implementation is known to work with Shibboleth IdP 3.2. There is some indication that ECP
41and ID-WSF profiles are supported by some other open source and commercial IdP
42systems, but none of them were tested.
43
44## X.509 authentication
45
46As it should be clear from the example below, ID-WSF requires that your IdP is configured to support
47__X.509 client certificate authentication__. The same applies to all TLS middleware you might have
48in front of your IdP, e.g. nginx, httpd, netscaler, etc. This is at least as complicated as it
49sounds, so good luck. Good starting points are:
50
51* [Tomcat SSLValve](https://tomcat.apache.org/tomcat-8.0-doc/api/org/apache/catalina/valves/SSLValve.html)
52* [X.509 Client-Side Certificate Auth with Nginx](http://nategood.com/client-side-certificate-authentication-in-ngi)
53
54> Things get easier if you want to use this library in ECP mode. Although ECP *does* support X.509 auth,
55> it is optional (you can use basic HTTP auth method).
56
57## Security
58
59- The client signs all outgoing AuthRequests.
60- The client expects incoming assertions to be both encrypted and signed.
61- `inResponseTo` validation is supported and enabled by default.
62- `NotBeforeOrAfter` is not validated, but is returned in `assertionInfo` object.
63- `wsa` profile does not work over plain HTTP, and never will.
64- `ecp` mode _should_ work over plain HTTP, but this is a very bad idea.
65
66## Install
67
68```
69$ npm install hana-saml-wsse
70```
71
72## IdP configuration
73
74The following configuration snippet assumes the following scenario:
75
76- A Service Provider idendified as `webserver-sp` is allowed to obtain a
77delegatable assertion using ECP at any time. Assertion is valid for 10 hours.
78- By itself, a delegatable assertion in not usable by any other SP other than
79`webserver-sp` as its `Audience` restriction is limited to `webserver-sp`.
80- However, for as long as delegatable assertion remains valid, `webserver-sp` can
81request additional, "delegated" assertions which will be valid for `database-sp`,
82each valid for 60 seconds. These delegated assertions are no further delegatable,
83i.e. `database-sp` is the final point of access.
84
85___
86
87> Note that, while requesting a delegated assertion, `webserver-sp` does not need
88> to present actual credentials of the user (generally, username and password), and it
89> is not expected to have them - instead, it presents a delegatable assertion as the
90> means of confirming that it has the authority to impersonate that user on `database-sp`
91> or elsewhere. The communication takes place over authenticated TLS channel, i.e.
92> IdP uses TLS to ensure it is actually talking to the SP to which the delegatable
93> assertion was originally issued. __In essence, this is the whole idea of how
94> assertion delegation works__.
95___
96
97```xml
98<!-- conf/relying-party.xml -->
99
100<!--
101 "delegation-predicate" is a reference to a bean that implements
102 com.google.common.base.Predicate<ProfileRequestContext<?,?>> interface.
103 It can be used to implement additional custom logic to selectively allow
104 or disallow delegation. In the most basic case, you want to implement a predicate that
105 always returns true.
106-->
107
108<bean parent="RelyingPartyByName" c:relyingPartyIds="#{{ 'webserver-sp' }}">
109 <property name="profileConfigurations">
110 <list>
111 <!-- serve long-lived delegatable assertions via ECP -->
112 <bean id="SAML2.ECP"
113 class="net.shibboleth.idp.saml.saml2.profile.config.ECPProfileConfiguration"
114 p:inboundInterceptorFlows="security-policy/saml2-ecp"
115 p:allowDelegation-ref="delegation-predicate"
116 p:assertionLifetime="PT600M"
117 />
118 <!-- serve short-lived delegated assertions via ID-WSF -->
119 <bean id="Liberty.SSOS"
120 class="net.shibboleth.idp.saml.idwsf.profile.config.SSOSProfileConfiguration"
121 p:inboundInterceptorFlows="security-policy/saml2-idwsf-ssos"
122 p:maximumTokenDelegationChainLength="1"
123 p:allowDelegation="false"
124 p:delegationPredicate-ref="delegation-predicate"
125 p:additionalAudiencesForAssertion="#{{ 'database-sp' }}"
126 p:assertionLifetime="PT1M"
127 />
128 </list>
129 </property>
130</bean>
131```
132
133## SP configuration
134
135SP metadata must inform IdP that SP is ready and willing to consume delegatable assertions,
136as shown below. The `Location` attribute of `AssertionConsumerService` must match `consumerURL` parameter
137of `hana-saml-wsse` client configuration, but this is a formality as SP is not expected
138to actually respond on that URL.
139
140```xml
141...
142<!-- SSOS -->
143<AssertionConsumerService
144 Binding="urn:oasis:names:tc:SAML:2.0:bindings:PAOS"
145 Location="https://my.org/Liberty/SSOS"/>
146
147<AttributeConsumingService>
148 <RequestedAttribute
149 NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
150 Name="urn:liberty:ssos:2006-08"
151 FriendlyName="assertionDelegation"
152 isRequired="false" />
153</AttributeConsumingService>
154...
155```
156
157## Usage
158
159The example below matches the IdP configuration above and:
160
1611. Binds to your Identity Provider's ECP endpoint using TLS transport.
1622. Authenticates using either user/password or X.509 certificate of the user.
1633. Retrieves, verifies and decrypts a delegatable assertion.
1644. Creates an ID-WSF AuthRequest using delegatable assertion as a security token.
1655. Binds to the ID-WSF endpoint using TLS transport.
1666. Authenticates using X.509 certificate of the SP.
1677. Retrieves, verifies and decrypts a delegate assertion.
1688. Tests it by using it as a security token to connect to a SAP HANA backend.
1699. Optionally repeats steps 4-7 every `deleg_test_repeat_ms` milliseconds.
170___
171
172```javascript
173// test.js
174var
175 hdb = require('hdb'),
176 precise = require('precise'),
177 moment = require('moment'),
178 xmlfmt = require('xmlfmt'),
179 WSS = require('hana-saml-wsse')
180;
181
182var
183 deleg_test_repeat_ms = 3000,
184 idpHost = 'idphost',
185 idpPort = 443,
186 http_ua = 'hana-wss-client/1.0',
187 hdb_conf = {
188 host: 'hanahost',
189 port: 30015
190 }
191;
192
193var conf = {
194 user : 'tj_holowaychuk',
195 pass : null, // leave blank for TLS CCA (@see user_key/user_cert)
196
197 idpHost : idpHost,
198 idpPort : idpPort,
199
200 idpId : 'idp-id',
201 spId : 'webserver-sp',
202
203 url: {
204 ecp : '/idp/profile/SAML2/SOAP/ECP',
205 wsa : '/idp/profile/IDWSF/SSOS'
206 },
207
208 consumerURL : 'https://my.org/Liberty/SSOS',
209
210 idp_cert : './idp.pem',
211
212 // used both for signing and X.509 auth (WSA only)
213 sp_key : './sp_private_key.pem',
214 sp_cert : './sp_public_key.pem',
215
216 // optional TLS CCA authentication (ECP only)
217 user_key : './user.key',
218 user_cert : './user.crt',
219
220 sig_alg : 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256',
221
222 tls_opt: {
223 hostname : idpHost,
224 port : idpPort,
225 method : 'POST',
226 headers : {
227 'Content-Type' : 'text/xml',
228 'Transfer-Encoding' : 'chunked',
229 'User-Agent' : http_ua
230 },
231 // die on bad IdP cert
232 rejectUnauthorized: true
233 },
234
235 log: console.log
236};
237
238var client = new WSS.client(conf);
239
240function hdbtest(assertion, cb) {
241 var hdbclient = hdb.createClient(hdb_conf);
242 hdbclient.connect({ assertion: assertion }, (err) => {
243 if (err) {
244 console.error('[hdb] error:', err);
245 } else {
246 console.log('[hdb] i am', hdbclient.get('user'));
247 }
248 hdbclient.end();
249 cb && cb(err);
250 });
251}
252
253client.get('ecp', (err, delegatableAssertion, assertionInfo) => {
254 if (err)
255 return conf.log('[ecp] error:', err);
256
257 conf.log('[ecp] rcvd delegatable assertion, expires',
258 moment(assertionInfo.notOnOrAfter).fromNow());
259
260 //conf.log(xmlfmt(delegatableAssertion))
261
262 var delegator = () => {
263 var timer = precise().start();
264 client.get('wsa', (err, assertion, assertionInfo) => {
265 if (err)
266 return conf.log('[wsa] error:', err);
267
268 //conf.log(xmlfmt(assertion));
269 //conf.log(assertion);
270
271 conf.log('[wsa] rcvd delegated assertion in',
272 (timer.stop().diff()/1000000000).toFixed(2) + 's,',
273 'expires', moment(assertionInfo.notOnOrAfter).fromNow());
274
275 hdbtest(assertion, () => {
276 if(!deleg_test_repeat_ms)
277 process.exit(0);
278 });
279 }, delegatableAssertion);
280 };
281
282 if (deleg_test_repeat_ms)
283 setInterval(delegator, deleg_test_repeat_ms);
284 else
285 delegator();
286});
287
288//:~
289```
290
291You should get something like:
292
293```
294$ node test.js
295
296[ecp] using tls cca with user key
297[ecp] rcvd delegatable assertion, expires in 10 hours
298[wsa] using tls cca with SP key
299[wsa] rcvd delegated assertion in 0.22s, expires in a minute
300[hdb] i am tj_holowaychuk
301[wsa] using tls cca with SP key
302[wsa] rcvd delegated assertion in 0.14s, expires in a minute
303[hdb] i am tj_holowaychuk
304[wsa] using tls cca with SP key
305[wsa] rcvd delegated assertion in 0.16s, expires in a minute
306[hdb] i am tj_holowaychuk
307[wsa] using tls cca with SP key
308[wsa] rcvd delegated assertion in 0.11s, expires in a minute
309[hdb] i am tj_holowaychuk
310[wsa] using tls cca with SP key
311[wsa] rcvd delegated assertion in 0.14s, expires in a minute
312^C
313
314```
315
316## Recommended reading
317
318SAML specs are fun:
319
320* [Overview of SAML assertion delegation scenarios](http://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-delegation-cs-01.pdf)
321* [SAML V2.0 Enhanced Client or Proxy (ECP)](https://wiki.oasis-open.org/security/SAML2EnhancedClientProfile)
322* [WS-Security SAML Token](http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.0.pdf)
323* [SAML Metadata Specification](https://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf)
324* [IDWSF-SAML Specification](http://www.projectliberty.org/resource_center/specifications/liberty_alliance_id_wsf_2_0_specifications/)
325* [Understanding WS-Security](https://msdn.microsoft.com/en-us/library/ms977327.aspx)
326* [WSA SOAP binding](https://www.w3.org/TR/2006/REC-ws-addr-soap-20060509/)
327* [urn:oasis:names:tc:SAML:2.0:cm:holder-of-key](http://hdknr.github.io/docs/identity/SamlHokProfile.html)
328
329## License
330
331MIT. Use at your own risk. As with all things SAML, always be sure you know what you are doing.