Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for subpaths in Auth0 domain [SDK-2963] #557

Merged
merged 9 commits into from
Nov 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions Auth0.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,6 @@
5B7EE47F20FCA0A200367724 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
5B7EE48220FCA0A200367724 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
5B7EE48420FCA0A200367724 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
5B7EE48520FCA0A200367724 /* OAuth2Mac.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = OAuth2Mac.entitlements; sourceTree = "<group>"; };
5B9262BF1ECF0CA800F4F6D3 /* BioAuthentication.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BioAuthentication.swift; sourceTree = "<group>"; };
5B9262C11ECF0CBA00F4F6D3 /* BioAuthenticationSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BioAuthenticationSpec.swift; path = Auth0Tests/BioAuthenticationSpec.swift; sourceTree = SOURCE_ROOT; };
5B9A54411E49E3AE004B5454 /* Auth0.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Auth0.plist; sourceTree = SOURCE_ROOT; };
Expand Down Expand Up @@ -671,7 +670,6 @@
5B7EE47D20FCA0A100367724 /* ViewController.swift */,
5B7EE47F20FCA0A200367724 /* Assets.xcassets */,
5B7EE48120FCA0A200367724 /* Main.storyboard */,
5B7EE48520FCA0A200367724 /* OAuth2Mac.entitlements */,
5B7EE48420FCA0A200367724 /* Info.plist */,
5C41F6E0244FA62200252548 /* Auth0.plist */,
);
Expand Down
4 changes: 2 additions & 2 deletions Auth0/Auth0.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public let defaultScope = "openid profile email"
- returns: Auth0 Authentication API
*/
public func authentication(clientId: String, domain: String, session: URLSession = .shared) -> Authentication {
return Auth0Authentication(clientId: clientId, url: .a0_url(domain), session: session)
return Auth0Authentication(clientId: clientId, url: .httpsURL(from: domain), session: session)
}

/**
Expand Down Expand Up @@ -122,7 +122,7 @@ public func users(token: String, session: URLSession = .shared, bundle: Bundle =
- returns: Auth0 Management API v2
*/
public func users(token: String, domain: String, session: URLSession = .shared) -> Users {
return Management(token: token, url: .a0_url(domain), session: session)
return Management(token: token, url: .httpsURL(from: domain), session: session)
}

func plistValues(bundle: Bundle) -> (clientId: String, domain: String)? {
Expand Down
40 changes: 20 additions & 20 deletions Auth0/Auth0Authentication.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ struct Auth0Authentication: Authentication {
}

func login(usernameOrEmail username: String, password: String, realm: String, audience: String?, scope: String) -> Request<Credentials, AuthenticationError> {
let resourceOwner = URL(string: "/oauth/token", relativeTo: self.url)!
let resourceOwner = URL(string: "oauth/token", relativeTo: self.url)!
var payload: [String: Any] = [
"username": username,
"password": password,
"grant_type": "http://auth0.com/oauth/grant-type/password-realm",
"client_id": self.clientId,
"realm": realm
]
]
payload["audience"] = audience
payload["scope"] = scope
return Request(session: session,
Expand All @@ -45,7 +45,7 @@ struct Auth0Authentication: Authentication {
}

func loginDefaultDirectory(withUsername username: String, password: String, audience: String?, scope: String) -> Request<Credentials, AuthenticationError> {
let resourceOwner = URL(string: "/oauth/token", relativeTo: self.url)!
let resourceOwner = URL(string: "oauth/token", relativeTo: self.url)!
var payload: [String: Any] = [
"username": username,
"password": password,
Expand All @@ -64,7 +64,7 @@ struct Auth0Authentication: Authentication {
}

func login(withOTP otp: String, mfaToken: String) -> Request<Credentials, AuthenticationError> {
let url = URL(string: "/oauth/token", relativeTo: self.url)!
let url = URL(string: "oauth/token", relativeTo: self.url)!
let payload: [String: Any] = [
"otp": otp,
"mfa_token": mfaToken,
Expand All @@ -81,7 +81,7 @@ struct Auth0Authentication: Authentication {
}

func login(withOOBCode oobCode: String, mfaToken: String, bindingCode: String?) -> Request<Credentials, AuthenticationError> {
let url = URL(string: "/oauth/token", relativeTo: self.url)!
let url = URL(string: "oauth/token", relativeTo: self.url)!
var payload: [String: Any] = [
"oob_code": oobCode,
"mfa_token": mfaToken,
Expand All @@ -103,7 +103,7 @@ struct Auth0Authentication: Authentication {
}

func login(withRecoveryCode recoveryCode: String, mfaToken: String) -> Request<Credentials, AuthenticationError> {
let url = URL(string: "/oauth/token", relativeTo: self.url)!
let url = URL(string: "oauth/token", relativeTo: self.url)!
let payload: [String: Any] = [
"recovery_code": recoveryCode,
"mfa_token": mfaToken,
Expand All @@ -121,7 +121,7 @@ struct Auth0Authentication: Authentication {
}

func multifactorChallenge(mfaToken: String, types: [String]?, authenticatorId: String?) -> Request<Challenge, AuthenticationError> {
let url = URL(string: "/mfa/challenge", relativeTo: self.url)!
let url = URL(string: "mfa/challenge", relativeTo: self.url)!
var payload: [String: String] = [
"mfa_token": mfaToken,
"client_id": self.clientId
Expand Down Expand Up @@ -186,7 +186,7 @@ struct Auth0Authentication: Authentication {
"password": password,
"connection": connection,
"client_id": self.clientId
]
]
payload["username"] = username
payload["user_metadata"] = userMetadata
if let rootAttributes = rootAttributes {
Expand All @@ -195,7 +195,7 @@ struct Auth0Authentication: Authentication {
}
}

let createUser = URL(string: "/dbconnections/signup", relativeTo: self.url)!
let createUser = URL(string: "dbconnections/signup", relativeTo: self.url)!
return Request(session: session,
url: createUser,
method: "POST",
Expand All @@ -211,7 +211,7 @@ struct Auth0Authentication: Authentication {
"connection": connection,
"client_id": self.clientId
]
let resetPassword = URL(string: "/dbconnections/change_password", relativeTo: self.url)!
let resetPassword = URL(string: "dbconnections/change_password", relativeTo: self.url)!
return Request(session: session,
url: resetPassword,
method: "POST",
Expand All @@ -227,12 +227,12 @@ struct Auth0Authentication: Authentication {
"connection": connection,
"send": type.rawValue,
"client_id": self.clientId
]
]
if case .WebLink = type, !parameters.isEmpty {
payload["authParams"] = parameters
}

let start = URL(string: "/passwordless/start", relativeTo: self.url)!
let start = URL(string: "passwordless/start", relativeTo: self.url)!
return Request(session: session,
url: start,
method: "POST",
Expand All @@ -248,8 +248,8 @@ struct Auth0Authentication: Authentication {
"connection": connection,
"send": type.rawValue,
"client_id": self.clientId
]
let start = URL(string: "/passwordless/start", relativeTo: self.url)!
]
let start = URL(string: "passwordless/start", relativeTo: self.url)!
return Request(session: session,
url: start,
method: "POST",
Expand All @@ -260,7 +260,7 @@ struct Auth0Authentication: Authentication {
}

func userInfo(withAccessToken accessToken: String) -> Request<UserInfo, AuthenticationError> {
let userInfo = URL(string: "/userinfo", relativeTo: self.url)!
let userInfo = URL(string: "userinfo", relativeTo: self.url)!
return Request(session: session,
url: userInfo,
method: "GET",
Expand All @@ -274,7 +274,7 @@ struct Auth0Authentication: Authentication {
let payload: [String: Any] = [
"client_id": self.clientId
]
let token = URL(string: "/oauth/token", relativeTo: self.url)!
let token = URL(string: "oauth/token", relativeTo: self.url)!
return Request(session: session,
url: token,
method: "POST",
Expand All @@ -300,7 +300,7 @@ struct Auth0Authentication: Authentication {
"client_id": self.clientId
]
payload["scope"] = scope
let oauthToken = URL(string: "/oauth/token", relativeTo: self.url)!
let oauthToken = URL(string: "oauth/token", relativeTo: self.url)!
return Request(session: session,
url: oauthToken,
method: "POST",
Expand All @@ -315,7 +315,7 @@ struct Auth0Authentication: Authentication {
"token": refreshToken,
"client_id": self.clientId
]
let oauthToken = URL(string: "/oauth/revoke", relativeTo: self.url)!
let oauthToken = URL(string: "oauth/revoke", relativeTo: self.url)!
return Request(session: session,
url: oauthToken,
method: "POST",
Expand All @@ -326,7 +326,7 @@ struct Auth0Authentication: Authentication {
}

func jwks() -> Request<JWKS, AuthenticationError> {
let jwks = URL(string: "/.well-known/jwks.json", relativeTo: self.url)!
let jwks = URL(string: ".well-known/jwks.json", relativeTo: self.url)!
return Request(session: session,
url: jwks,
method: "GET",
Expand All @@ -341,7 +341,7 @@ struct Auth0Authentication: Authentication {

private extension Auth0Authentication {
func login(username: String, otp: String, realm: String, audience: String?, scope: String) -> Request<Credentials, AuthenticationError> {
let url = URL(string: "/oauth/token", relativeTo: self.url)!
let url = URL(string: "oauth/token", relativeTo: self.url)!
var payload: [String: Any] = [
"username": username,
"otp": otp,
Expand Down
6 changes: 3 additions & 3 deletions Auth0/Auth0WebAuth.swift
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,8 @@ final class Auth0WebAuth: WebAuth {

func clearSession(federated: Bool, callback: @escaping (Bool) -> Void) {
let endpoint = federated ?
URL(string: "/v2/logout?federated", relativeTo: self.url)! :
URL(string: "/v2/logout", relativeTo: self.url)!
URL(string: "v2/logout?federated", relativeTo: self.url)! :
URL(string: "v2/logout", relativeTo: self.url)!

let returnTo = URLQueryItem(name: "returnTo", value: self.redirectURL?.absoluteString)
let clientId = URLQueryItem(name: "client_id", value: self.clientId)
Expand All @@ -181,7 +181,7 @@ final class Auth0WebAuth: WebAuth {
state: String?,
organization: String?,
invitation: String?) -> URL {
let authorize = URL(string: "/authorize", relativeTo: self.url)!
let authorize = URL(string: "authorize", relativeTo: self.url)!
var components = URLComponents(url: authorize, resolvingAgainstBaseURL: true)!
var items: [URLQueryItem] = []
var entries = defaults
Expand Down
20 changes: 6 additions & 14 deletions Auth0/NSURL+Auth0.swift
Original file line number Diff line number Diff line change
@@ -1,20 +1,12 @@
import Foundation

public extension URL {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the breaking change.

/**
Returns an Auth0 domain URL given a domain
extension URL {

- parameter domain: name of your Auth0 account

- returns: URL of your Auth0 account
*/
static func a0_url(_ domain: String) -> URL {
let urlString: String
if !domain.hasPrefix("https") {
urlString = "https://\(domain)"
} else {
urlString = domain
}
static func httpsURL(from domain: String) -> URL {
let prefix = !domain.hasPrefix("https") ? "https://" : ""
let suffix = !domain.hasSuffix("/") ? "/" : ""
let urlString = "\(prefix)\(domain)\(suffix)"
return URL(string: urlString)!
}

}
8 changes: 4 additions & 4 deletions Auth0/Users.swift
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ extension Users {
extension Management: Users {

func get(_ identifier: String, fields: [String], include: Bool) -> Request<ManagementObject, ManagementError> {
let userPath = "/api/v2/users/\(identifier)"
let userPath = "api/v2/users/\(identifier)"
var component = components(baseURL: self.url as URL, path: userPath)
let value = fields.joined(separator: ",")
if !value.isEmpty {
Expand All @@ -266,7 +266,7 @@ extension Management: Users {
}

func patch(_ identifier: String, attributes: UserPatchAttributes) -> Request<ManagementObject, ManagementError> {
let userPath = "/api/v2/users/\(identifier)"
let userPath = "api/v2/users/\(identifier)"
let component = components(baseURL: self.url as URL, path: userPath)

return Request(session: self.session, url: component.url!, method: "PATCH", handle: self.managementObject, payload: attributes.dictionary, headers: self.defaultHeaders, logger: self.logger, telemetry: self.telemetry)
Expand All @@ -291,13 +291,13 @@ extension Management: Users {
}

private func link(_ identifier: String, payload: [String: Any]) -> Request<[ManagementObject], ManagementError> {
let identitiesPath = "/api/v2/users/\(identifier)/identities"
let identitiesPath = "api/v2/users/\(identifier)/identities"
let url = components(baseURL: self.url as URL, path: identitiesPath).url!
return Request(session: self.session, url: url, method: "POST", handle: self.managementObjects, payload: payload, headers: self.defaultHeaders, logger: self.logger, telemetry: self.telemetry)
}

func unlink(identityId: String, provider: String, fromUserId identifier: String) -> Request<[ManagementObject], ManagementError> {
let identityPath = "/api/v2/users/\(identifier)/identities/\(provider)/\(identityId)"
let identityPath = "api/v2/users/\(identifier)/identities/\(provider)/\(identityId)"
let url = components(baseURL: self.url as URL, path: identityPath).url!
return Request(session: self.session, url: url, method: "DELETE", handle: self.managementObjects, headers: self.defaultHeaders, logger: self.logger, telemetry: self.telemetry)
}
Expand Down
2 changes: 1 addition & 1 deletion Auth0/WebAuth.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public func webAuth(session: URLSession = .shared, bundle: Bundle = Bundle.main)
- returns: Auth0 WebAuth component
*/
public func webAuth(clientId: String, domain: String, session: URLSession = .shared) -> WebAuth {
return Auth0WebAuth(clientId: clientId, url: .a0_url(domain), session: session)
return Auth0WebAuth(clientId: clientId, url: .httpsURL(from: domain), session: session)
}

/// WebAuth Authentication using Auth0
Expand Down
84 changes: 67 additions & 17 deletions Auth0Tests/Auth0Spec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,24 +46,74 @@ class Auth0Spec: QuickSpec {

describe("endpoints") {

it("should return authentication endpoint with clientId and domain") {
let auth = Auth0.authentication(clientId: ClientId, domain: Domain)
expect(auth).toNot(beNil())
expect(auth.clientId) == ClientId
expect(auth.url.absoluteString) == "https://\(Domain)"
}

context("without trailing slash") {

it("should return authentication endpoint with clientId and domain") {
let auth = Auth0.authentication(clientId: ClientId, domain: Domain)
expect(auth).toNot(beNil())
expect(auth.clientId) == ClientId
expect(auth.url.absoluteString) == "https://\(Domain)/"
}

it("should return authentication endpoint with domain url") {
let domain = "https://mycustomdomain.com"
let auth = Auth0.authentication(clientId: ClientId, domain: domain)
expect(auth.url.absoluteString) == "\(domain)/"
}

it("should return authentication endpoint with domain url and a subpath") {
let domain = "https://mycustomdomain.com/foo"
let auth = Auth0.authentication(clientId: ClientId, domain: domain)
expect(auth.url.absoluteString) == "\(domain)/"
}

it("should return authentication endpoint with domain url and subpaths") {
let domain = "https://mycustomdomain.com/foo/bar"
let auth = Auth0.authentication(clientId: ClientId, domain: domain)
expect(auth.url.absoluteString) == "\(domain)/"
}

it("should return users endpoint") {
let users = Auth0.users(token: "token", domain: Domain)
expect(users.token) == "token"
expect(users.url.absoluteString) == "https://\(Domain)/"
}

it("should return authentication endpoint with domain url") {
let domain = "https://mycustomdomain.com"
let auth = Auth0.authentication(clientId: ClientId, domain: domain)
expect(auth.url.absoluteString) == domain
}

it("should return users endopoint") {
let users = Auth0.users(token: "token", domain: Domain)
expect(users.token) == "token"
expect(users.url.absoluteString) == "https://\(Domain)"
context("with trailing slash") {

it("should return authentication endpoint with clientId and domain") {
let auth = Auth0.authentication(clientId: ClientId, domain: "\(Domain)/")
expect(auth).toNot(beNil())
expect(auth.clientId) == ClientId
expect(auth.url.absoluteString) == "https://\(Domain)/"
}

it("should return authentication endpoint with domain url") {
let domain = "https://mycustomdomain.com/"
let auth = Auth0.authentication(clientId: ClientId, domain: domain)
expect(auth.url.absoluteString) == domain
}

it("should return authentication endpoint with domain url with a subpath") {
let domain = "https://mycustomdomain.com/foo/"
let auth = Auth0.authentication(clientId: ClientId, domain: domain)
expect(auth.url.absoluteString) == domain
}

it("should return authentication endpoint with domain url with subpaths") {
let domain = "https://mycustomdomain.com/foo/bar/"
let auth = Auth0.authentication(clientId: ClientId, domain: domain)
expect(auth.url.absoluteString) == domain
}

it("should return users endpoint") {
let users = Auth0.users(token: "token", domain: Domain)
expect(users.token) == "token"
expect(users.url.absoluteString) == "https://\(Domain)/"
}

}

}
Expand All @@ -75,13 +125,13 @@ class Auth0Spec: QuickSpec {

it("should return authentication endpoint with account from plist") {
let auth = Auth0.authentication(bundle: bundle)
expect(auth.url.absoluteString) == "https://samples.auth0.com"
expect(auth.url.absoluteString) == "https://samples.auth0.com/"
expect(auth.clientId) == "CLIENT_ID"
}

it("should return users endpoint with domain from plist") {
let users = Auth0.users(token: "TOKEN", bundle: bundle)
expect(users.url.absoluteString) == "https://samples.auth0.com"
expect(users.url.absoluteString) == "https://samples.auth0.com/"
}

}
Expand Down
Loading