-
Notifications
You must be signed in to change notification settings - Fork 19
/
adobe-id-for-short-client-token
executable file
·108 lines (80 loc) · 3.79 KB
/
adobe-id-for-short-client-token
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
#!/usr/bin/env python3
import re
import sys
import click
import requests
DEFAULT_REGISTRY_URL = "https://libraryregistry.librarysimplified.org"
CLIENT_TOKEN_RE = re.compile(r'''
^
(?P<library>[^|]+) \| # Any number of characters up to a pipe
(?P<timestamp>[0-9]+) \| # Epoch timestamp, any number of digits
(?P<patron_id>[-A-Za-z0-9]{36}) \| # The patron id is a UUID, 36 characters long
(?P<signature_hash>.*) # Everything after the third pipe
$
''', re.IGNORECASE | re.VERBOSE)
REGISTRY_RESPONSE_RE = re.compile(r'''<user>(?P<user_id>[^<]+?)</user>''', re.IGNORECASE)
class InvalidTokenException(Exception):
...
def decompose_token(token):
if "drm:clientToken" in token:
token = token.replace("<drm:clientToken>", "").replace("</drm:clientToken>", "")
m = CLIENT_TOKEN_RE.match(token)
if not m:
raise InvalidTokenException(f"Invalid token: {token}")
else:
return m.groups() # Tuple of library, timestamp, patron_id, signature_hash
@click.command()
@click.argument('token')
@click.option('--registry-url', default=DEFAULT_REGISTRY_URL, metavar='<URL>',
help="URL of the library registry you're testing against")
def main(token, registry_url):
"""
Retrieve an Adobe ID from a Short Client Token.
This script doesn't import any code from circulation or core. It
tests an integration based on HTTP via the requests package.
A short token is a four part, pipe-separated string which follows this pattern:
\b
<library-code>|<epoch-timestamp>|<patron-id>|<signature-hash>
Example:
\b
NYNYPL|1621462513|3e0d6602-2446-4f1a-bcad-4e68bcffdfc1|xzu4JDv93sjAEzx1sSIxyWrXn;zXD62;vsR:LT1y8M0@
"""
try:
(library, timestamp, patron_id, signature_hash) = decompose_token(token)
except InvalidTokenException as exc:
click.echo(str(exc))
sys.exit(1)
click.echo("\nThe supplied Short Client Token was well formed, and decomposes to:\n")
click.echo(f" Library code: {library}")
click.echo(f" Timestamp: {timestamp}")
click.echo(f" Patron identifier: {patron_id}")
click.echo(f" Signature: {signature_hash}\n")
if registry_url.endswith("/"):
registry_url = registry_url[:-1]
signin_url = registry_url + "/AdobeAuth/SignIn"
username = "|".join([library, timestamp, patron_id])
signin_payload_lines = [
'<signInRequest method="standard" xmlns="http://ns.adobe.com/adept">',
f" <username>{username}</username>",
f" <password>{signature_hash}</password>",
"</signInRequest>",
]
click.echo(f"\nRequesting {signin_url} with payload:\n")
for line in signin_payload_lines:
click.echo(f" {line}")
response = requests.post(signin_url, data="".join(signin_payload_lines))
click.echo("\nRegistry server responded with:\n")
for line in response.content.decode('utf8').split("\n"):
click.echo(f" {line}")
click.echo()
user_id_match = REGISTRY_RESPONSE_RE.search(response.content.decode('utf8'))
if user_id_match:
click.echo(click.style("SUCCESS ", fg="green", bold=True), nl=False)
click.echo(f"Adobe ID for this patron is {user_id_match.group('user_id')}", nl=False)
click.echo(click.style(" SUCCESS", fg="green", bold=True))
else:
click.echo(click.style("ERROR ", fg="red", bold=True), nl=False)
click.echo("Supplied token could not be turned into an Adobe ID", nl=False)
click.echo(click.style(" ERROR", fg="red", bold=True))
if __name__ == '__main__':
main()