This repository has been archived by the owner on Jun 13, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdigest-amqp.txt
338 lines (273 loc) · 14.8 KB
/
digest-amqp.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
This document describes Digest-AMQP, a specification for exchanging Digest authentication data between a front-end requesting application and a back-end credentials service over an AMQP network.
* Name: [email protected]
* Editor: Pieter Hintjens <[email protected]>
++ License
Copyright (c) 2008 iMatix Corporation.
This Specification is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
This Specification is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, see <http://www.gnu.org/licenses>.
++ Change Process
This document is governed by the [email protected] specification.
++ Summary
Digest-AMQP is a specification for exchanging authentication data between two peers, a front-end requesting application and a back-end credentials server over an AMQP network. This specification consists of three components:
# An XML format for credential Request messages, sent from a front-end application to a back-end application.
# An XML format for credential Response messages, send from the back-end application to the front-end application.
# AMQP routing rules for ensuring that the front-end and back-end application can properly exchange Request and Response messages.
Digest-AMQP is not in itself a secured scheme, it assumes that either the AMQP network lies entirely within a secured zone, or else that the data is carried over some unspecified secured AMQP transport.
++ Purpose
The intended purpose of Digest-AMQP is to allow the separation of front-end applications that need to authenticate users, from back-end credential services. Specifically, the front-end applications that Digest-AMQP targets are web services using Digest authentication[1]. A typical back-end credential service would be LDAP[2].
++ Architecture
The following diagram shows the general architecture of a Digest-AMQP deployment.
[[=image digest-amqp.png size="medium"]]
The Request (in red) travels as follows:
# A browser requests a method on a resource that is protected by Digest authentication.
# The WWW server challenges the browser to provide credentials, which it does.
# The WWW server asks for credentials from the Digest-AMQP requestor.
# The Digest-AMQP requestor formats a Digest-AMQP Request message and sends this to the AMQP server via an AMQP API layer.
# The AMQP server routes the Request to the Digest-AMQP service, which retrieves the message via its AMQP API layer.
# The Digest-AMQP service requests digest or password information from the credentials service.
The Response (in blue) then travels as follows:
# The credentials service provides the Digest-AMQP service with the necessary credentials data.
# The Digest-AMQP service formats a Response message and sends this to the AMQP server via its AMQP API layer.
# The AMQP server routes the Response to the Digest-AMQP requestor, which retrieves the message via its AMQP API layer.
# The Digest-AMQP requestor provides the WWW server with the credentials.
# The WWW server validates the brower-provided credentials and either accepts or denies the browser's request.
One of the key features of the Digest scheme is that passwords do not cross the network. That is, the browser and the WWW server, and the Digest-AMQP requestor and the Digest-AMQP service exchange digests of the password along with other data.
Note that:
* The web server must be capable of executing a plug-in module to implement Digest-AMQP.
* The credentials service must be capable either of returning a properly formed Digest, or of providing the clear-text password to the Digest-AMQP service.
++ Specification
+++ Request and Response formats
The Digest-AMQP request is an XML document with this format:
[[code]]
<digest-amqp
xmlns="http://www.imatix.com/schema/digest-amqp"
version="1.0">
<request
user = "user-name"
realm = "realm"
algorithm = "algorithm"
reply_to = "routing key"
/>
</digest-amqp>
[[/code]]
The user, realm, and algorithm properties have the meaning defined in RFC 2617. The reply_to property is the name of a queue created by the requestor.
The Digest-AMQP response is an XML document with this format:
[[code]]
<digest-amqp
xmlns="http://www.imatix.com/schema/digest-amqp"
version="1.0">
<response
user = "user-name"
realm = "realm"
algorithm = "algorithm"
digest = "digest-string"
/>
</digest-amqp>
[[/code]]
The user, realm, and algorithm properties are identical to that supplied in the Request. The digest is the hex value of H(user ":" realm ":" password), where H is the hashing algorithm. If the user and/or realm are not valid, the digest will be an empty string.
+++ Message routing
Digest-AMQP uses the RestMS[3] convention of addressing queues by name via the amq.direct exchange. In this section we'll provide recipes for both requestor and service, in both AMQP and RestMS styles.
The AMQP service works as follows:
* It declares a queue, normally called "Digest-AMQP" and declared as non-exclusive.
* It binds this queue to the "amq.direct" exchange, using the routing key "Digest-AMQP".
* It consumes from that queue and waits for incoming requests.
* When it receives a request, it executes it, and prepares a response.
* It publishes the response to the "amq.direct" exchange using the reply_to property of the request as the routing key.
The AMQP requestor works as follows:
* It declares a queue, normally named by the server, and declared as exclusive, for responses.
* It binds this queue to the "amq.direct" exchange, using the queue name as routing key.
* It prepares a request and publishes that to the "amq.direct" exchange using the routing key "Digest-AMQP", and the 'mandatory' option set to TRUE.
* It consumes from that queue and waits for incoming messages.
* When it receives a response, it processes it.
* If it receives a returned message, it can conclude that the Digest-AMQP service is not running.
Either the requestor and/or service can be implemented using RestMS rather than AMQP. The RestMS service works as follows:
* It creates a service feed called "Digest-AMQP".
* It creates a server-named pipe.
* It creates a join between its pipe and the Digest-AMQP feed using the address "*@Digest-AMQP".
* It waits for a request message on the pipe, and when one arrives, it executes it and prepares a response.
* It posts the response to an address consisting of the reply_to property of the request followed by "@amq.direct".
* It deletes the message from the pipe.
The RestMS requestor works as follows:
* It creates a server-named pipe, for responses.
* It creates a join between its pipe and the amq.direct feed using the address "{pipe-name}@amq.direct".
* It prepares a request, setting the reply_to property to the name of its pipe.
* It posts the request to the address "request@Digest-AMQP".
* It waits for a response message on the pipe.
* When it receives a response, it processes it, and deletes the message from the pipe.
In the RestMS case, if the Digest-AMQP service is not running, the requestor's attempt to post to "request@Digest-AMQP" will fail with an error. RestMS does not use AMQP's 'mandatory' and returned message mechanism.
Note that all strings used in routing are case-sensitive.
++ Worked example
We use the example from RFC 2617. The requestor requests credentials for the user "Mufasa" in the realm "[email protected]" by sending this Request:
[[code]]
Exchange: amq.direct
Routing-key: Digest-AMQP
Content-type: application/x-Digest-AMQP
<digest-amqp
xmlns="http://www.imatix.com/schema/digest-amqp"
version="1.0">
<request
user = "Mufasa"
realm = "[email protected]"
algorithm = "MD5"
reply_to = "queue-0123"
/>
</digest-amqp>
[[/code]]
The actual format of the request is a binary AMQP Basic.Publish command. Here we use a simple text format to represent the significant arguments: exchange and routing-key are arguments to Basic.Publish and content-type is a property of the content. The XML is passed as the content body of the Basic.Publish commands.
The password for this user/realm is "Circle Of Life". The Digest-AMQP service calculates the hash as MD5("Mufasa:[email protected]:Circle Of Life"), which "939e7578ed9e3c518a452acee763bce9". It sends this Response:
[[code]]
Exchange: amq.direct
Routing-key: queue-0123
Content-type: application/x-Digest-AMQP
<digest-amqp
xmlns="http://www.imatix.com/schema/digest-amqp"
version="1.0">
<response
user = "Mufasa"
realm = "[email protected]"
algorithm = "MD5"
digest = "939e7578ed9e3c518a452acee763bce9"
/>
</digest-amqp>
[[/code]]
++ Sample implementations
This is an implementation of a Digest-AMQP service in [http://www.openamq.org/doc:prog-pal PAL]. It demonstrates the AMQP routing aspects:
[[code]]
<?xml?>
<!--
This is a demo Digest-AMQP service that shows how to send
a response back to a Digest-AMQP requestor. The response is
hard-coded on the RFC2617 example.
-->
<pal script = "amq_pal_gen">
<session>
<queue_declare
queue = "Digest-AMQP" />
<queue_bind
queue = "$queue"
exchange = "amq.direct"
routing_key = "$queue" />
<basic_consume
queue = "$queue" />
<echo>I: Digest-AMQP service is registered</echo>
<repeat>
<wait />
<basic_arrived>
<set name = "content_type"
value = "$content_type" />
<if name = "content_type"
value = "application/x-Digest-AMQP">
<echo>I: received valid request</echo>
</if>
<else>
<echo>W: received invalid request</echo>
</else>
</basic_arrived>
<basic_content
content_type = "application/x-Digest-AMQP">
<digest-amqp
xmlns=\"http://www.imatix.com/schema/digest-amqp\"
version=\"1.0\">
<response
user = \"Mufasa\"
realm = \"[email protected]\"
algorithm = \"MD5\"
digest = \"939e7578ed9e3c518a452acee763bce9\"
/>
</digest-amqp>
</basic_content>
<basic_publish
exchange = "amq.direct"
routing_key = "$reply_to"
/>
</repeat>
</session>
</pal>
[[/code]]
Here is a corresponding Digest-AMQP requestor in PAL:
[[code]]
<?xml?>
<!--
This is a demo Digest-AMQP requestor that shows how to send
a request to a Digest-AMQP service. The request is based
on the RFC2617 example.
-->
<pal script = "amq_pal_gen">
<session>
<queue_declare
exclusive = "1" />
<queue_bind
queue = "$queue"
exchange = "amq.direct"
routing_key = "$queue" />
<basic_consume
queue = "$queue" />
<echo>I: sending Digest-AMQP request...</echo>
<basic_content
content_type = "application/x-Digest-AMQP">
<digest-amqp
xmlns=\"http://www.imatix.com/schema/digest-amqp\"
version=\"1.0\">
<request
user = \"Mufasa\"
realm = \"[email protected]\"
algorithm = \"MD5\"
reply_to = \"$queue\"
/>
</digest-amqp>
</basic_content>
<basic_publish
exchange = "amq.direct"
routing_key = "Digest-AMQP"
mandatory = "1"
immediate = "1"
/>
<wait
timeout = "1000" />
<basic_arrived>
<set
name = "content_type"
value = "$content_type" />
<if name = "content_type"
value = "application/x-Digest-AMQP">
<echo>I: received valid response</echo>
</if>
<else>
<echo>E: unrecognised response</echo>
</else>
</basic_arrived>
<empty>
<echo>E: no response from Digest-AMQP service</echo>
</empty>
<basic_returned>
<echo>E: Digest-AMQP service is not running</echo>
</basic_returned>
</session>
</pal>
[[/code]]
Here is an example Perl program that calculates the MD5 hash for a given user, realm, and password:
[[code]]
#! /usr/bin/perl
#
use Digest::MD5;
# These arguments are passed on the command line
my ($user, $realm, $password) = @ARGV;
die "E: syntax: command user realm password\n" unless $password;
print "digest = \"".Digest::MD5::md5_hex("$user:$realm:$password")."\"\n";
[[/code]]
Further fragments showing how to calculate digests in other programming languages are given in the Apache password format documentation.[4]
++ Security implications
* The Digest-AMQP design does not attempt to secure data traveling over the AMQP network. We assume that this network is sufficiently secure.
* Passwords never leave the Digest-AMQP service, or the credentials service if it is capable of generating the neccessary digests.
* All parties that know the digest can falsely represent the user. Thus, if the WWW server is compromised, and it has stored digests, those digests can be used to create valid responses for Digest Authentication challenges, to any server relying on the same digest.
* The MD5 algorithm is not considered secure[5]. Other algorithms such as SHA-1 and the SHA-2 family may be considered. However, these are not implemented by browsers[6] so currently, only the MD5 algorithm can be used.
* HTTP Digest Authentication does not encrypt data.
Considering these security implications, applications should weigh the interest of using a certificate based security model, for data that is considered sensitive.
++ References
[1] HTTP Authentication: Basic and Digest Access Authentication ([http://tools.ietf.org/html/rfc2617 RFC 2617])
[2] Lightweight Directory Access Protocol (LDAP): Technical Specification Road Map ([http://tools.ietf.org/html/rfc4510 RFC 4510])
[3] [email protected].
[4] Apache HTTP Server Version 2.2 [http://httpd.apache.org/docs/2.2/misc/password_encryptions.html Password Formats].
[5] MD5 collisions crack CA certificate ([http://lwn.net/Articles/313134/ Heise Online])
[6] Digest Authentication is not secure ([https://bugzilla.mozilla.org/show_bug.cgi?id=472823 Mozilla bug 472823])