7
//
7
//
8
8
9
#import " TDBrowserIDAuthorizer.h"
9
#import " TDBrowserIDAuthorizer.h"
10
-
10
+ # import " TDBase64.h "
11
11
12
static NSMutableDictionary * sAssertions ;
12
static NSMutableDictionary * sAssertions ;
13
13
14
14
15
@implementation TDBrowserIDAuthorizer
15
@implementation TDBrowserIDAuthorizer
16
16
17
17
18
+ static NSDictionary * decodeComponent (NSArray * components, NSUInteger index) {
19
+ NSData * bodyData = [TDBase64 decodeURLSafe: components[index]];
20
+ if (!bodyData)
21
+ return nil ;
22
+ return $castIf (NSDictionary , [TDJSON JSONObjectWithData: bodyData options: 0 error: NULL ]);
23
+ }
24
+
25
+
26
+ static bool parseAssertion (NSString * assertion,
27
+ NSString ** outEmail, NSString ** outOrigin, NSDate ** outExp)
28
+ {
29
+ // https://github.com/mozilla/id-specs/blob/prod/browserid/index.md
30
+ // http://self-issued.info/docs/draft-jones-json-web-token-04.html
31
+ NSArray * components = [assertion componentsSeparatedByString: @" ." ];
32
+ if (components.count < 4 )
33
+ return false ;
34
+ NSDictionary * body = decodeComponent (components, 1 );
35
+ NSDictionary * principal = $castIf (NSDictionary , body[@" principal" ]);
36
+ *outEmail = $castIf (NSString , principal[@" email" ]);
37
+
38
+ body = decodeComponent (components, 3 );
39
+ *outOrigin = $castIf (NSString , body[@" aud" ]);
40
+ NSNumber * exp = $castIf (NSNumber , body[@" exp" ]);
41
+ *outExp = exp ? [NSDate dateWithTimeIntervalSince1970: exp.doubleValue / 1000.0 ] : nil ;
42
+ return *outEmail != nil && *outOrigin != nil && *outExp != nil ;
43
+ }
44
+
45
+
18
+ (NSURL *) originForSite : (NSURL *)url {
46
+ (NSURL *) originForSite : (NSURL *)url {
19
NSString * scheme = url.scheme .lowercaseString ;
47
NSString * scheme = url.scheme .lowercaseString ;
20
NSMutableString * str = [NSMutableString stringWithFormat: @" %@ ://%@ " ,
48
NSMutableString * str = [NSMutableString stringWithFormat: @" %@ ://%@ " ,
@@ -30,27 +58,27 @@ + (NSURL*) originForSite: (NSURL*)url {
30
}
58
}
31
59
32
60
33
- + (void ) registerAssertion : (NSString *)assertion
61
+ + (NSString *) registerAssertion : (NSString *)assertion {
34
- forEmailAddress : (NSString *)email
62
+ NSString * email, *origin;
35
- toSite : (NSURL *)site
63
+ NSDate * exp;
36
- {
64
+ if (!parseAssertion (assertion, &email, &origin, &exp))
65
+ return nil ;
66
+ id key = @[email, origin];
37
@synchronized (self) {
67
@synchronized (self) {
38
if (!sAssertions )
68
if (!sAssertions )
39
sAssertions = [NSMutableDictionary dictionary ];
69
sAssertions = [NSMutableDictionary dictionary ];
40
- id key = @[email, [self originForSite: site]];
41
sAssertions [key] = assertion;
70
sAssertions [key] = assertion;
42
}
71
}
72
+ return email;
43
}
73
}
44
74
45
75
46
+ (NSString *) takeAssertionForEmailAddress : (NSString *)email
76
+ (NSString *) takeAssertionForEmailAddress : (NSString *)email
47
site : (NSURL *)site
77
site : (NSURL *)site
48
{
78
{
79
+ id key = @[email, [[self originForSite: site] absoluteString ]];
49
@synchronized (self) {
80
@synchronized (self) {
50
- id key = @[email, [self originForSite: site]];
81
+ return sAssertions [key];
51
- NSString * assertion = sAssertions [key];
52
- // [sAssertions removeObjectForKey: key];
53
- return assertion;
54
}
82
}
55
}
83
}
56
84
@@ -69,6 +97,18 @@ - (id) initWithEmailAddress: (NSString*)emailAddress {
69
}
97
}
70
98
71
99
100
+ - (NSString *) assertionForSite : (NSURL *)site {
101
+ NSString * assertion = [[self class ] takeAssertionForEmailAddress: _emailAddress site: site];
102
+ if (!assertion)
103
+ return nil ;
104
+ NSString * email, *origin;
105
+ NSDate * exp;
106
+ if (!parseAssertion (assertion, &email, &origin, &exp) || exp.timeIntervalSinceNow < 0 )
107
+ return nil ;
108
+ return assertion;
109
+ }
110
+
111
+
72
- (NSString *) authorizeURLRequest : (NSMutableURLRequest *)request
112
- (NSString *) authorizeURLRequest : (NSMutableURLRequest *)request
73
forRealm : (NSString *)realm
113
forRealm : (NSString *)realm
74
{
114
{
@@ -91,10 +131,36 @@ - (NSString*) loginPath {
91
131
92
132
93
- (NSDictionary *) loginParametersForSite : (NSURL *)site {
133
- (NSDictionary *) loginParametersForSite : (NSURL *)site {
94
- NSString * assertion = [[self class ] takeAssertionForEmailAddress: _emailAddress site: site];
134
+ NSString * assertion = [self assertionForSite: site];
95
- if (!assertion)
135
+ return assertion ? @{@" assertion" : assertion} : nil ;
96
- return nil ;
97
- return @{@" assertion" : assertion};
98
}
136
}
99
137
100
@end
138
@end
139
+
140
+
141
+
142
+
143
+ TestCase (TEBrowserIDAuthorizer) {
144
+ NSString * email, *origin;
145
+ NSDate * exp;
146
+ CAssert (!parseAssertion (@" " , &email, &origin, &exp));
147
+
148
+ // This is an assertion generated by persona.org on 1/13/2013.
149
+ NSString* sampleAssertion = @"eyJhbGciOiJSUzI1NiJ9.eyJwdWJsaWMta2V5Ijp7ImFsZ29yaXRobSI6IkRTIiwieSI6ImNhNWJiYTYzZmI4MDQ2OGE0MjFjZjgxYTIzN2VlMDcwYTJlOTM4NTY0ODhiYTYzNTM0ZTU4NzJjZjllMGUwMDk0ZWQ2NDBlOGNhYmEwMjNkYjc5ODU3YjkxMzBlZGNmZGZiNmJiNTUwMWNjNTk3MTI1Y2NiMWQ1ZWQzOTVjZTMyNThlYjEwN2FjZTM1ODRiOWIwN2I4MWU5MDQ4NzhhYzBhMjFlOWZkYmRjYzNhNzNjOTg3MDAwYjk4YWUwMmZmMDQ4ODFiZDNiOTBmNzllYzVlNDU1YzliZjM3NzFkYjEzMTcxYjNkMTA2ZjM1ZDQyZmZmZjQ2ZWZiZDcwNjgyNWQiLCJwIjoiZmY2MDA0ODNkYjZhYmZjNWI0NWVhYjc4NTk0YjM1MzNkNTUwZDlmMWJmMmE5OTJhN2E4ZGFhNmRjMzRmODA0NWFkNGU2ZTBjNDI5ZDMzNGVlZWFhZWZkN2UyM2Q0ODEwYmUwMGU0Y2MxNDkyY2JhMzI1YmE4MWZmMmQ1YTViMzA1YThkMTdlYjNiZjRhMDZhMzQ5ZDM5MmUwMGQzMjk3NDRhNTE3OTM4MDM0NGU4MmExOGM0NzkzMzQzOGY4OTFlMjJhZWVmODEyZDY5YzhmNzVlMzI2Y2I3MGVhMDAwYzNmNzc2ZGZkYmQ2MDQ2MzhjMmVmNzE3ZmMyNmQwMmUxNyIsInEiOiJlMjFlMDRmOTExZDFlZDc5OTEwMDhlY2FhYjNiZjc3NTk4NDMwOWMzIiwiZyI6ImM1MmE0YTBmZjNiN2U2MWZkZjE4NjdjZTg0MTM4MzY5YTYxNTRmNGFmYTkyOTY2ZTNjODI3ZTI1Y2ZhNmNmNTA4YjkwZTVkZTQxOWUxMzM3ZTA3YTJlOWUyYTNjZDVkZWE3MDRkMTc1ZjhlYmY2YWYzOTdkNjllMTEwYjk2YWZiMTdjN2EwMzI1OTMyOWU0ODI5YjBkMDNiYmM3ODk2YjE1YjRhZGU1M2UxMzA4NThjYzM0ZDk2MjY5YWE4OTA0MWY0MDkxMzZjNzI0MmEzODg5NWM5ZDViY2NhZDRmMzg5YWYxZDdhNGJkMTM5OGJkMDcyZGZmYTg5NjIzMzM5N2EifSwicHJpbmNpcGFsIjp7ImVtYWlsIjoiamVuc0Btb29zZXlhcmQuY29tIn0sImlhdCI6MTM1ODI5NjIzNzU3NywiZXhwIjoxMzU4MzgyNjM3NTc3LCJpc3MiOiJsb2dpbi5wZXJzb25hLm9yZyJ9.RnDK118nqL2wzpLCVRzw1MI4IThgeWpul9jPl6ypyyxRMMTurlJbjFfs-BXoPaOem878G8-4D2eGWS6wd307k7xlPysevYPogfFWxK_eDHwkTq3Ts91qEDqrdV_JtgULC8c1LvX65E0TwW_GL_TM94g3CvqoQnGVxxoaMVye4ggvR7eOZjimWMzUuu4Lo9Z-VBHBj7XM0UMBie57CpGwH4_Wkv0V_LHZRRHKdnl9ISp_aGwfBObTcHG9v0P3BW9vRrCjihIn0SqOJQ9obl52rMf84GD4Lcy9NIktzfyka70xR9Sh7ALotW7rWywsTzMTu3t8AzMz2MJgGjvQmx49QA~eyJhbGciOiJEUzEyOCJ9.eyJleHAiOjEzNTgyOTY0Mzg0OTUsImF1ZCI6Imh0dHA6Ly9sb2NhbGhvc3Q6NDk4NC8ifQ.4FV2TrUQffDya0MOxOQlzJQbDNvCPF2sfTIJN7KOLvvlSFPknuIo5g";
150
+ CAssert (parseAssertion (sampleAssertion, &email, &origin, &exp));
151
+ CAssertEqual (email, @" jens@mooseyard.com" );
152
+ CAssertEqual (origin, @" http://localhost:4984/" );
153
+ CAssertEq ((SInt64)exp.timeIntervalSinceReferenceDate , 379989238 );
154
+
155
+ // Register and retrieve the sample assertion:
156
+ NSURL * originURL = [NSURL URLWithString: origin];
157
+ CAssertEqual ([TDBrowserIDAuthorizer registerAssertion: sampleAssertion], email);
158
+ NSString * gotAssertion = [TDBrowserIDAuthorizer takeAssertionForEmailAddress: email
159
+ site: originURL];
160
+ CAssertEqual (gotAssertion, sampleAssertion);
161
+
162
+ // -assertionForSite: should return nil because the assertion has expired by now:
163
+ TDBrowserIDAuthorizer* auth = [[TDBrowserIDAuthorizer alloc ] initWithEmailAddress: email];
164
+ CAssertEqual (auth.emailAddress , email);
165
+ CAssertEqual ([auth assertionForSite: originURL], nil );
166
+ }
0 commit comments