Skip to content

Commit 0feab70

Browse files
authored
Merge pull request #48 from auth0/feat-challenge-using-full-url-for-audience
Add support for appliance
2 parents efa8fc2 + 5598916 commit 0feab70

7 files changed

+544
-43
lines changed

Guardian/Authentication.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ struct RSAAuthentication: Authentication {
144144
var jwtPayload: [String: Any] = [
145145
"iat": currentTime,
146146
"exp": currentTime + RSAAuthentication.challengeResponseExpiresInSecs,
147-
"aud": self.api.baseUrl.absoluteString,
147+
"aud": self.api.baseUrl.appendingPathComponent("api/resolve-transaction").absoluteString,
148148
"iss": self.enrollment.deviceIdentifier,
149149
"sub": challenge,
150150
"auth0_guardian_method": "push",

Guardian/Guardian.swift

Lines changed: 140 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,25 @@ import Foundation
3737
- seealso: Guardian.API
3838
*/
3939
public func api(forDomain domain: String, session: URLSession = .shared) -> API {
40-
return APIClient(baseUrl: url(from: domain)!, session: session)
40+
return api(url: url(from: domain)!, session: session)
41+
}
42+
43+
/**
44+
Creates a low level API client for Guardian MFA server
45+
46+
```
47+
let api = Guardian.api(url: URL(string: "https://tenant.guardian.auth0.com/")!)
48+
```
49+
50+
- parameter url: URL of your Guardian server
51+
- parameter session: session to use for network requests
52+
53+
- returns: an Guardian API client
54+
55+
- seealso: Guardian.API
56+
*/
57+
public func api(url: URL, session: URLSession = .shared) -> API {
58+
return APIClient(baseUrl: url, session: session)
4159
}
4260

4361
/**
@@ -63,6 +81,30 @@ public func authentication(forDomain domain: String, andEnrollment enrollment: E
6381
return RSAAuthentication(api: client, enrollment: enrollment)
6482
}
6583

84+
/**
85+
Creates an authentication manager for a Guardian enrollment
86+
87+
```
88+
let enrollment: Enrollment = // the object you obtained when enrolling
89+
let authenticator = Guardian
90+
.authentication(url: URL(string: "https://tenant.guardian.auth0.com/")!,
91+
andEnrollment: enrollment)
92+
```
93+
94+
- parameter url: URL of your Guardian server
95+
- parameter andEnrollment: the enrollment that will be used to handle
96+
authentication
97+
- parameter session: session to use for network requests
98+
99+
- returns: an `Authentication` instance
100+
101+
- seealso: Guardian.Authentication
102+
*/
103+
public func authentication(url: URL, andEnrollment enrollment: Enrollment, session: URLSession = .shared) -> Authentication {
104+
let client = api(url: url, session: session)
105+
return RSAAuthentication(api: client, enrollment: enrollment)
106+
}
107+
66108
/**
67109
Creates a request to enroll from a Guardian enrollment URI
68110

@@ -112,6 +154,55 @@ public func enroll(forDomain domain: String, session: URLSession = .shared, usin
112154
return EnrollRequest(api: client, enrollmentUri: uri, notificationToken: notificationToken, keyPair: keyPair)
113155
}
114156

157+
/**
158+
Creates a request to enroll from a Guardian enrollment URI
159+
160+
You'll have to create a new pair of RSA keys for the enrollment.
161+
The keys will be stored on the keychain, and we'll later access them by `tag`,
162+
so you should use a unique identifier every time you create them.
163+
164+
```
165+
let rsaKeyPair = RSAKeyPair.new(usingPublicTag: "com.auth0.guardian.enroll.public",
166+
privateTag: "com.auth0.guardian.enroll.private")
167+
```
168+
169+
You will also need an enroll uri (from a Guardian QR code for example) and the
170+
APNS token for the device.
171+
172+
Finally, to create an enrollment you just use it like this:
173+
174+
```
175+
let enrollUri: String = // obtained from a Guardian QR code
176+
let apnsToken: String = // apple push notification service token for this device
177+
178+
Guardian
179+
.enroll(url: URL(string: "https://tenant.guardian.auth0.com/")!,
180+
usingUri: enrollUri,
181+
notificationToken: apnsToken,
182+
keyPair: rsaKeyPair)
183+
.start { result in
184+
switch result {
185+
case .success(let enrollment):
186+
// we have the enrollment data, save it for later usages
187+
case .failure(let cause):
188+
// something failed
189+
}
190+
}
191+
```
192+
193+
- parameter url: URL of your Guardian server
194+
- parameter session: session to use for network requests
195+
- parameter usingUri: the enrollment URI
196+
- parameter notificationToken: the APNS token of the device
197+
- parameter keyPair: the RSA key pair
198+
199+
- returns: a request to create an enrollment
200+
*/
201+
public func enroll(url: URL, session: URLSession = .shared, usingUri uri: String, notificationToken: String, keyPair: RSAKeyPair) -> EnrollRequest {
202+
let client = api(url: url, session: session)
203+
return EnrollRequest(api: client, enrollmentUri: uri, notificationToken: notificationToken, keyPair: keyPair)
204+
}
205+
115206
/**
116207
Creates a request to enroll from a Guardian enrollment ticket
117208

@@ -160,6 +251,54 @@ public func enroll(forDomain domain: String, session: URLSession = .shared, usin
160251
return EnrollRequest(api: client, enrollmentTicket: ticket, notificationToken: notificationToken, keyPair: keyPair)
161252
}
162253

254+
/**
255+
Creates a request to enroll from a Guardian enrollment ticket
256+
257+
You'll have to create a new pair of RSA keys for the enrollment.
258+
The keys will be stored on the keychain, and we'll later access them by `tag`,
259+
so you should use a unique identifier every time you create them.
260+
261+
```
262+
let rsaKeyPair = RSAKeyPair.new(usingPublicTag: "com.auth0.guardian.enroll.public",
263+
privateTag: "com.auth0.guardian.enroll.private")
264+
```
265+
266+
You will also need an enroll ticket and the APNS token for the device.
267+
268+
Finally, to create an enrollment you just use it like this:
269+
270+
```
271+
let enrollTicket: String = // obtained from a Guardian QR code or email
272+
let apnsToken: String = // apple push notification service token for this device
273+
274+
Guardian
275+
.enroll(url: URL(string: "https://tenant.guardian.auth0.com/")!,
276+
usingTicket: enrollTicket,
277+
notificationToken: apnsToken,
278+
keyPair: rsaKeyPair)
279+
.start { result in
280+
switch result {
281+
case .success(let enrollment):
282+
// we have the enrollment data, save it for later usages
283+
case .failure(let cause):
284+
// something failed
285+
}
286+
}
287+
```
288+
289+
- parameter url: URL of your Guardian server
290+
- parameter session: session to use for network requests
291+
- parameter usingTicket: the enrollment ticket
292+
- parameter notificationToken: the APNS token of the device
293+
- parameter keyPair: the RSA key pair
294+
295+
- returns: a request to create an enrollment
296+
*/
297+
public func enroll(url: URL, session: URLSession = .shared, usingTicket ticket: String, notificationToken: String, keyPair: RSAKeyPair) -> EnrollRequest {
298+
let client = api(url: url, session: session)
299+
return EnrollRequest(api: client, enrollmentTicket: ticket, notificationToken: notificationToken, keyPair: keyPair)
300+
}
301+
163302
/**
164303
Parses and returns the data about the push notification's authentication
165304
request.

GuardianTests/APIClientSpec.swift

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class APIClientSpec: QuickSpec {
3030

3131
override func spec() {
3232

33-
let client = APIClient(baseUrl: URL(string: "https://\(Domain)/")!, session: URLSession.shared)
33+
let client = APIClient(baseUrl: ValidURL, session: URLSession.shared)
3434

3535
beforeEach {
3636
stub(condition: { _ in return true }) { _ in
@@ -45,7 +45,7 @@ class APIClientSpec: QuickSpec {
4545
describe("enroll") {
4646

4747
beforeEach {
48-
stub(condition: isMobileEnroll(domain: Domain)
48+
stub(condition: isMobileEnroll(baseUrl: ValidURL)
4949
&& hasTicketAuth(ValidTransactionId)
5050
&& hasAtLeast([
5151
"identifier": ValidDeviceIdentifier,
@@ -100,14 +100,14 @@ class APIClientSpec: QuickSpec {
100100
describe("resolve-transaction") {
101101

102102
beforeEach {
103-
stub(condition: isResolveTransaction(domain: Domain)) { _ in
103+
stub(condition: isResolveTransaction(baseUrl: ValidURL)) { _ in
104104
return errorResponse(statusCode: 404, errorCode: "invalid_token", message: "Invalid transaction token")
105105
}.name = "Missing authentication"
106-
stub(condition: isResolveTransaction(domain: Domain)
106+
stub(condition: isResolveTransaction(baseUrl: ValidURL)
107107
&& hasBearerToken(ValidTransactionToken)) { req in
108108
return errorResponse(statusCode: 401, errorCode: "invalid_challenge", message: "Invalid challenge_response")
109109
}.name = "Invalid challenge_response"
110-
stub(condition: isResolveTransaction(domain: Domain)
110+
stub(condition: isResolveTransaction(baseUrl: ValidURL)
111111
&& hasBearerToken(ValidTransactionToken)
112112
&& hasAtLeast([
113113
"challenge_response": ValidChallengeResponse
@@ -153,14 +153,14 @@ class APIClientSpec: QuickSpec {
153153
describe("delete enrollment") {
154154

155155
beforeEach {
156-
stub(condition: isDeleteEnrollment(domain: Domain)) { _ in
156+
stub(condition: isDeleteEnrollment(baseUrl: ValidURL)) { _ in
157157
return errorResponse(statusCode: 404, errorCode: "invalid_token", message: "Invalid transaction token")
158158
}.name = "Missing authentication"
159-
stub(condition: isDeleteEnrollment(domain: Domain)
159+
stub(condition: isDeleteEnrollment(baseUrl: ValidURL)
160160
&& hasBearerToken(ValidEnrollmentToken)) { _ in
161161
return errorResponse(statusCode: 404, errorCode: "enrollment_not_found", message: "Enrollment not found")
162162
}.name = "Enrollment not found"
163-
stub(condition: isDeleteEnrollment(domain: Domain, enrollmentId: ValidEnrollmentId)
163+
stub(condition: isDeleteEnrollment(baseUrl: ValidURL, enrollmentId: ValidEnrollmentId)
164164
&& hasBearerToken(ValidEnrollmentToken)) { _ in
165165
return successResponse()
166166
}.name = "Valid delete enrollment"
@@ -206,14 +206,14 @@ class APIClientSpec: QuickSpec {
206206
describe("update enrollment") {
207207

208208
beforeEach {
209-
stub(condition: isUpdateEnrollment(domain: Domain)) { _ in
209+
stub(condition: isUpdateEnrollment(baseUrl: ValidURL)) { _ in
210210
return errorResponse(statusCode: 404, errorCode: "invalid_token", message: "Invalid transaction token")
211211
}.name = "Missing authentication"
212-
stub(condition: isUpdateEnrollment(domain: Domain)
212+
stub(condition: isUpdateEnrollment(baseUrl: ValidURL)
213213
&& hasBearerToken(ValidEnrollmentToken)) { _ in
214214
return errorResponse(statusCode: 404, errorCode: "enrollment_not_found", message: "Enrollment not found")
215215
}.name = "Enrollment not found"
216-
stub(condition: isUpdateEnrollment(domain: Domain, enrollmentId: ValidEnrollmentId)
216+
stub(condition: isUpdateEnrollment(baseUrl: ValidURL, enrollmentId: ValidEnrollmentId)
217217
&& hasBearerToken(ValidEnrollmentToken)) { req in
218218
let payload = req.a0_payload
219219
let pushCredentials = payload?["push_credentials"] as? [String: String]

0 commit comments

Comments
 (0)