Skip to content

Commit

Permalink
Merge pull request #336 from auth0/enterprise_support
Browse files Browse the repository at this point in the history
Enterprise Connection only authentication
  • Loading branch information
hzalaz authored Nov 8, 2016
2 parents 11b2f84 + f99cfcd commit 48ad17b
Show file tree
Hide file tree
Showing 20 changed files with 922 additions and 46 deletions.
10 changes: 10 additions & 0 deletions App/Assets.xcassets/AppIcon.appiconset/Contents.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "29x29",
Expand Down
1 change: 0 additions & 1 deletion App/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ class ViewController: UIViewController {
withImage: LazyImage(name: "ic_slack")
)
}
.allowedConnections(["github", "instagram", "Username-Password-Authentication", "slack"])
},
actionButton(withTitle: "LOGIN WITH CUSTOM STYLE") {
return Lock
Expand Down
28 changes: 28 additions & 0 deletions Lock.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@
objects = {

/* Begin PBXBuildFile section */
5B09717C1DC8F229003AA88F /* EnterpriseDomain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B09717B1DC8F229003AA88F /* EnterpriseDomain.swift */; };
5B09717E1DC8F292003AA88F /* EnterpriseDomainInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B09717D1DC8F292003AA88F /* EnterpriseDomainInteractor.swift */; };
5B0971801DC8F5C4003AA88F /* EnterpriseDomainPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B09717F1DC8F5C4003AA88F /* EnterpriseDomainPresenter.swift */; };
5B0971821DC8FAC5003AA88F /* EnterpriseDomainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B0971811DC8FAC5003AA88F /* EnterpriseDomainView.swift */; };
5BA563F11DD117550002D3AB /* EnterpriseDomainInteractorSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA563EF1DD1171F0002D3AB /* EnterpriseDomainInteractorSpec.swift */; };
5BC6BC0C1DCBDDC9002EA81C /* EnterpriseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BC6BC0B1DCBDDC9002EA81C /* EnterpriseView.swift */; };
5BCED4C71DD1FEAA00E2CE8A /* EnterpriseDomainPresenterSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BCED4C51DD1FCF200E2CE8A /* EnterpriseDomainPresenterSpec.swift */; };
5F14565A1D5130E80085DF9C /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F1456591D5130E80085DF9C /* Colors.swift */; };
5F14565B1D5237180085DF9C /* LazyImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F92C68E1D50EAC200CCE6C0 /* LazyImage.swift */; };
5F14565C1D5237210085DF9C /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F1456591D5130E80085DF9C /* Colors.swift */; };
Expand Down Expand Up @@ -191,6 +198,13 @@
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
5B09717B1DC8F229003AA88F /* EnterpriseDomain.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = EnterpriseDomain.swift; path = Lock/EnterpriseDomain.swift; sourceTree = SOURCE_ROOT; };
5B09717D1DC8F292003AA88F /* EnterpriseDomainInteractor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = EnterpriseDomainInteractor.swift; path = Lock/EnterpriseDomainInteractor.swift; sourceTree = SOURCE_ROOT; };
5B09717F1DC8F5C4003AA88F /* EnterpriseDomainPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = EnterpriseDomainPresenter.swift; path = Lock/EnterpriseDomainPresenter.swift; sourceTree = SOURCE_ROOT; };
5B0971811DC8FAC5003AA88F /* EnterpriseDomainView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = EnterpriseDomainView.swift; path = Lock/EnterpriseDomainView.swift; sourceTree = SOURCE_ROOT; };
5BA563EF1DD1171F0002D3AB /* EnterpriseDomainInteractorSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnterpriseDomainInteractorSpec.swift; sourceTree = "<group>"; };
5BC6BC0B1DCBDDC9002EA81C /* EnterpriseView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = EnterpriseView.swift; path = Lock/EnterpriseView.swift; sourceTree = SOURCE_ROOT; };
5BCED4C51DD1FCF200E2CE8A /* EnterpriseDomainPresenterSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnterpriseDomainPresenterSpec.swift; sourceTree = "<group>"; };
5F1456591D5130E80085DF9C /* Colors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Colors.swift; path = Lock/Colors.swift; sourceTree = SOURCE_ROOT; };
5F14565D1D5237820085DF9C /* DatabaseView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DatabaseView.swift; path = Lock/DatabaseView.swift; sourceTree = SOURCE_ROOT; };
5F1C498D1D8360AA005B74FC /* Style.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Style.swift; path = Lock/Style.swift; sourceTree = SOURCE_ROOT; };
Expand Down Expand Up @@ -364,9 +378,11 @@
5FC4348E1D1E0A57005188BC /* DatabaseAuthenticable.swift */,
5F508FF61D1D868900EAA650 /* DatabaseInteractor.swift */,
5F73CDD91D30957900D8D8D1 /* DatabasePasswordInteractor.swift */,
5B09717D1DC8F292003AA88F /* EnterpriseDomainInteractor.swift */,
5FBE5CBD1D3E5C7B0038536D /* MultifactorAuthenticatable.swift */,
5FBE5CBF1D3E5E0A0038536D /* MultifactorInteractor.swift */,
5F73CDD71D3093BF00D8D8D1 /* PasswordRecoverable.swift */,
5B09717B1DC8F229003AA88F /* EnterpriseDomain.swift */,
5F57DFD11D4FE59800C54DA8 /* OAuth2Authenticatable.swift */,
5F57DFD31D4FE64700C54DA8 /* Auth0OAuth2Interactor.swift */,
5F2496B21D665A5600A1C6E2 /* DatabaseUserCreator.swift */,
Expand All @@ -377,6 +393,7 @@
5F508FF81D1DB01D00EAA650 /* Interactors */ = {
isa = PBXGroup;
children = (
5BA563EF1DD1171F0002D3AB /* EnterpriseDomainInteractorSpec.swift */,
5F508FF91D1DB1C200EAA650 /* DatabaseInteractorSpec.swift */,
5F73CDDB1D309BE900D8D8D1 /* DatabasePasswordInteractorSpec.swift */,
5FBE5CC11D3E5EF50038536D /* MultifactorInteractorSpec.swift */,
Expand All @@ -402,6 +419,7 @@
children = (
5F1C49921D8360DF005B74FC /* LoadingView.swift */,
5F73CDD31D3073BE00D8D8D1 /* DatabaseForgotPasswordView.swift */,
5B0971811DC8FAC5003AA88F /* EnterpriseDomainView.swift */,
5F50900D1D1DF40400EAA650 /* DatabaseOnlyView.swift */,
5FBE5CB91D3E59B90038536D /* MultifactorCodeView.swift */,
5FC434851D1DF769005188BC /* View.swift */,
Expand All @@ -423,6 +441,7 @@
isa = PBXGroup;
children = (
5F73CDDD1D30B16900D8D8D1 /* DatabaseForgotPasswordPresenterSpec.swift */,
5BCED4C51DD1FCF200E2CE8A /* EnterpriseDomainPresenterSpec.swift */,
5F5F98D31D21E3890016FC22 /* DatabasePresenterSpec.swift */,
5FBE5CC91D3EA1380038536D /* MultifactorPresenterSpec.swift */,
5F57DFCD1D4FBE5A00C54DA8 /* AuthPresenterSpec.swift */,
Expand Down Expand Up @@ -516,6 +535,7 @@
children = (
5F1C498F1D8360BF005B74FC /* ConnectionLoadingPresenter.swift */,
5F73CDD51D30790500D8D8D1 /* DatabaseForgotPasswordPresenter.swift */,
5B09717F1DC8F5C4003AA88F /* EnterpriseDomainPresenter.swift */,
5FC434891D1DF82A005188BC /* DatabasePresenter.swift */,
5F73CDCF1D30250900D8D8D1 /* MessagePresenter.swift */,
5FBE5CC51D3E7F9D0038536D /* MultifactorPresenter.swift */,
Expand Down Expand Up @@ -613,6 +633,7 @@
5F99AA931D1BABFC00D27842 /* SecondaryButton.swift */,
5F51EE671D1C88FC0024BCD6 /* SignUpView.swift */,
5F51EE691D1CBC830024BCD6 /* SingleInputView.swift */,
5BC6BC0B1DCBDDC9002EA81C /* EnterpriseView.swift */,
5FD6772B1D4C303C004B87C4 /* AuthButton.swift */,
);
path = Components;
Expand Down Expand Up @@ -881,6 +902,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
5B09717E1DC8F292003AA88F /* EnterpriseDomainInteractor.swift in Sources */,
5F5F98DA1D22EF490016FC22 /* Router.swift in Sources */,
5F14565A1D5130E80085DF9C /* Colors.swift in Sources */,
5F57DFC91D4F87CE00C54DA8 /* AuthCollectionView.swift in Sources */,
Expand Down Expand Up @@ -910,8 +932,10 @@
5F2496B61D665AA800A1C6E2 /* InputValidationError.swift in Sources */,
5FFC54FE1D37E3F700579581 /* Routes.swift in Sources */,
5F1C49931D8360DF005B74FC /* LoadingView.swift in Sources */,
5B0971801DC8F5C4003AA88F /* EnterpriseDomainPresenter.swift in Sources */,
5FC434861D1DF769005188BC /* View.swift in Sources */,
5FDB41CE1D2C79FD00166B67 /* Operations.swift in Sources */,
5B09717C1DC8F229003AA88F /* EnterpriseDomain.swift in Sources */,
5F51EE681D1C88FC0024BCD6 /* SignUpView.swift in Sources */,
5F57DFD41D4FE64700C54DA8 /* Auth0OAuth2Interactor.swift in Sources */,
5F57DFD21D4FE59800C54DA8 /* OAuth2Authenticatable.swift in Sources */,
Expand All @@ -922,8 +946,10 @@
5F92C68F1D50EAC200CCE6C0 /* LazyImage.swift in Sources */,
5F2496BA1D665AE900A1C6E2 /* DatabaseAuthenticatableError.swift in Sources */,
5F57DFC61D4F79DD00C54DA8 /* AuthStyle.swift in Sources */,
5B0971821DC8FAC5003AA88F /* EnterpriseDomainView.swift in Sources */,
5FBE5CC61D3E7F9D0038536D /* MultifactorPresenter.swift in Sources */,
5FEAE2101D1A5691005C0028 /* HeaderView.swift in Sources */,
5BC6BC0C1DCBDDC9002EA81C /* EnterpriseView.swift in Sources */,
5F99AA8C1D1B3F1300D27842 /* InputField.swift in Sources */,
5FBE5CBA1D3E59B90038536D /* MultifactorCodeView.swift in Sources */,
5F1C49901D8360BF005B74FC /* ConnectionLoadingPresenter.swift in Sources */,
Expand Down Expand Up @@ -956,6 +982,7 @@
5F6C01551D91656100198ACD /* UsernameValidatorSpec.swift in Sources */,
5F2496BE1D67ADB300A1C6E2 /* EmailValidatorSpec.swift in Sources */,
5FBE5CCA1D3EA1380038536D /* MultifactorPresenterSpec.swift in Sources */,
5BA563F11DD117550002D3AB /* EnterpriseDomainInteractorSpec.swift in Sources */,
5F92C68D1D50E47100CCE6C0 /* AuthStyleSpec.swift in Sources */,
5F92C68B1D4FE90F00CCE6C0 /* Auth0OAuth2InteractorSpec.swift in Sources */,
5F5090081D1DE7BA00EAA650 /* NetworkStub.swift in Sources */,
Expand All @@ -973,6 +1000,7 @@
5FBE5CC81D3EA0EA0038536D /* Mocks.swift in Sources */,
5F57DFCE1D4FBE5A00C54DA8 /* AuthPresenterSpec.swift in Sources */,
5F92C6911D510AFE00CCE6C0 /* LazyImageSpec.swift in Sources */,
5BCED4C71DD1FEAA00E2CE8A /* EnterpriseDomainPresenterSpec.swift in Sources */,
5F50900A1D1DEE9A00EAA650 /* Constants.swift in Sources */,
5FE50DBD1D79B8AD00D82290 /* CDNLoaderInteractorSpec.swift in Sources */,
5F390E8D1D63B99300FC549C /* LoggerSpec.swift in Sources */,
Expand Down
8 changes: 8 additions & 0 deletions Lock/CDNLoaderInteractor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ struct CDNLoaderInteractor: RemoteConnectionLoader, Loggable {
connections.database(name: connection.name, requiresUsername: requiresUsername, usernameValidator: connection.usernameValidation)
}
}
info.enterprise.forEach { strategy in
strategy.connections.forEach { connection in
let domain = connection.json["domain_aliases"] as! [String]
connections.enterprise(name: connection.name, domains: domain)
}
}
info.oauth2.forEach { strategy in
strategy.connections.forEach { connections.social(name: $0.name, style: AuthStyle.style(forStrategy: strategy.name, connectionName: $0.name)) }
}
Expand All @@ -108,6 +114,8 @@ private struct ClientInfo {
var auth0: StrategyInfo? { return strategies.filter({ $0.name == "auth0" }).first }

var oauth2: [StrategyInfo] { return strategies.filter { $0.name != "auth0" && !passwordlessStrategyNames.contains($0.name) && !enterpriseStrategyNames.contains($0.name) } }

var enterprise: [StrategyInfo] { return strategies.filter { $0.name != "auth0" && !passwordlessStrategyNames.contains($0.name) && enterpriseStrategyNames.contains($0.name) } }

let passwordlessStrategyNames = [
"email",
Expand Down
8 changes: 8 additions & 0 deletions Lock/ConnectionBuildable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@ public protocol ConnectionBuildable: Connections {
- seeAlso: AuthStyle
*/
mutating func oauth2(name name: String, style: AuthStyle)

/**
Adds a new enterprise connection
- parameter name: name of the connection
- parameter domain: array of enterprise domains
*/
mutating func enterprise(name name: String, domains: [String])
}

public extension ConnectionBuildable {
Expand Down
2 changes: 1 addition & 1 deletion Lock/ConnectionLoadingPresenter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,4 @@ class ConnectionLoadingPresenter: Presentable, Loggable {
}
return LoadingView()
}
}
}
7 changes: 7 additions & 0 deletions Lock/Connections.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import Foundation
public protocol Connections {
var database: DatabaseConnection? { get }
var oauth2: [OAuth2Connection] { get }
var enterprise: [EnterpriseConnection] {get}

var isEmpty: Bool { get }

Expand Down Expand Up @@ -59,3 +60,9 @@ public struct SocialConnection: OAuth2Connection {
public let name: String
public let style: AuthStyle
}

public struct EnterpriseConnection : OAuth2Connection {
public let name: String
public var style: AuthStyle { return AuthStyle(name: self.name) }
public let domains: [String]
}
6 changes: 3 additions & 3 deletions Lock/DatabasePasswordInteractor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,12 @@ struct DatabasePasswordInteractor: PasswordRecoverable {
func requestEmail(callback: (PasswordRecoverableError?) -> ()) {
guard let email = self.email else { return callback(.NonValidInput) }
guard let connection = self.connections.database?.name else { return callback(.NoDatabaseConnection) }

self.authentication
.resetPassword(email: email, connection: connection)
.start {
guard case .Success = $0 else { return callback(.EmailNotSent) }
callback(nil)
}
}
}
}
}
32 changes: 32 additions & 0 deletions Lock/EnterpriseDomain.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// EnterpriseDomain.swift
//
// Copyright (c) 2016 Auth0 (http://auth0.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

import Foundation

protocol HRDAuthenticatable {
var email: String? { get }
var validEmail: Bool { get }

mutating func updateEmail(value: String?) throws

func login(callback: (OAuth2AuthenticatableError?) -> ())
}
67 changes: 67 additions & 0 deletions Lock/EnterpriseDomainInteractor.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// EnterpriseDomainInteractor.swift
//
// Copyright (c) 2016 Auth0 (http://auth0.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

import Foundation
import Auth0

struct EnterpriseDomainInteractor: HRDAuthenticatable {

var email: String? = nil
var validEmail: Bool = false
var connection: EnterpriseConnection? = nil

let connections: [EnterpriseConnection]
let emailValidator: InputValidator = EmailValidator()
let authenticator: OAuth2Authenticatable

init(connections: [EnterpriseConnection], authentication: OAuth2Authenticatable) {
self.connections = connections
self.authenticator = authentication
}

private func validateDomain(connections: [EnterpriseConnection], value: String?) -> EnterpriseConnection? {

guard let domain = value?.componentsSeparatedByString("@").last else { return nil }
return connections.filter { $0.domains.contains(domain) }.first
}

mutating func updateEmail(value: String?) throws {

validEmail = false
connection = nil

email = value?.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
if let error = emailValidator.validate(value) {
throw error
}
validEmail = true

self.connection = validateDomain(connections, value: email)
}

func login(callback: (OAuth2AuthenticatableError?) -> ()) {
guard let connection = self.connection else { return callback(.NoConnectionAvailable) }

authenticator.login(connection.name, callback: callback)

}
}
Loading

0 comments on commit 48ad17b

Please sign in to comment.