Skip to content

Commit

Permalink
MX3PidAddManager: Add User-Interactive Auth to /account/3pid/add
Browse files Browse the repository at this point in the history
  • Loading branch information
manuroe committed Oct 24, 2019
1 parent e188251 commit 9f77ce8
Show file tree
Hide file tree
Showing 8 changed files with 214 additions and 7 deletions.
3 changes: 3 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
Changes in Matrix iOS SDK in 0.xx.xx (2019-xx-xx)
===============================================

Improvements:
* MX3PidAddManager: Add User-Interactive Auth to /account/3pid/add (vector-im/riot-ios#2744).

Bug fix:
* Room members who left are listed with the actual members (vector-im/riot-ios#2737).

Expand Down
5 changes: 3 additions & 2 deletions MatrixSDK/Contrib/Swift/MXRestClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1381,13 +1381,14 @@ public extension MXRestClient {
- parameters:
- sid: the session id provided during the 3PID validation session.
- clientSecret: the same secret key used in the validation session.
- authParameters: The additional authentication information for the user-interactive authentication API.
- completion: A block object called when the operation completes.
- response: Indicates whether the operation was successful.

- returns: a `MXHTTPOperation` instance.
*/
@nonobjc @discardableResult func addThirdPartyIdentifierOnly(withSessionId sid: String, clientSecret: String, completion: @escaping (_ response: MXResponse<Void>) -> Void) -> MXHTTPOperation {
return __add3PIDOnly(withSessionId: sid, clientSecret: clientSecret, success: currySuccess(completion), failure: curryFailure(completion))
@nonobjc @discardableResult func addThirdPartyIdentifierOnly(withSessionId sid: String, clientSecret: String, authParameters: [String: Any]?, completion: @escaping (_ response: MXResponse<Void>) -> Void) -> MXHTTPOperation {
return __add3PIDOnly(withSessionId: sid, clientSecret: clientSecret, authParams: authParameters, success: currySuccess(completion), failure: curryFailure(completion))
}

/**
Expand Down
15 changes: 15 additions & 0 deletions MatrixSDK/Contrib/Swift/ThreePidAdd/MX3PidAddManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ public extension MX3PidAddManager {
return __tryFinaliseAddEmailSession(session, success: currySuccess(completion), failure: curryFailure(completion))
}

@nonobjc func tryFinaliseAddEmailSession(_ session: MX3PidAddSession, password: String?, completion: @escaping (_ response: MXResponse<Void>) -> Void) -> Void {
return __tryFinaliseAddEmailSession(session, withPassword: password, success: currySuccess(completion), failure: curryFailure(completion))
}

@nonobjc func tryFinaliseAddEmailSession(_ session: MX3PidAddSession, authParams: [String: Any]?, completion: @escaping (_ response: MXResponse<Void>) -> Void) -> Void {
return __tryFinaliseAddEmailSession(session, authParams: authParams, success: currySuccess(completion), failure: curryFailure(completion))
}

// MARK: - Add MSISDN
@nonobjc @discardableResult func startAddPhoneNumberSession(_ phoneNumber: String, countryCode: String?, completion: @escaping (_ response: MXResponse<Void>) -> Void) -> MX3PidAddSession {
Expand All @@ -46,6 +53,14 @@ public extension MX3PidAddManager {
return __finaliseAddPhoneNumber(session, withToken: token, success: currySuccess(completion), failure: curryFailure(completion))
}

@nonobjc func finaliseAddPhoneNumberSession(_ session: MX3PidAddSession, token: String, password: String?, completion: @escaping (_ response: MXResponse<Void>) -> Void) -> Void {
return __finaliseAddPhoneNumber(session, withToken: token, password: password, success: currySuccess(completion), failure: curryFailure(completion))
}

@nonobjc func finaliseAddPhoneNumberSession(_ session: MX3PidAddSession, token: String, authParams: [String: Any]?, completion: @escaping (_ response: MXResponse<Void>) -> Void) -> Void {
return __finaliseAddPhoneNumber(session, withToken: token, authParams: authParams, success: currySuccess(completion), failure: curryFailure(completion))
}


// MARK: - Bind Email
@nonobjc @discardableResult func startIdentityServerSession(withEmail email: String, bind: Bool, completion: @escaping (_ response: MXResponse<Bool>) -> Void) -> MX3PidAddSession {
Expand Down
2 changes: 2 additions & 0 deletions MatrixSDK/MXRestClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -1606,6 +1606,7 @@ typedef MXHTTPOperation* (^MXRestClientIdentityServerAccessTokenHandler)(void (^
@param sid the session id provided during the 3PID validation session.
@param clientSecret the same secret key used in the validation session.
@param authParameters The additional authentication information for the user-interactive authentication API.
@param success A block object called when the operation succeeds.
@param failure A block object called when the operation fails.
Expand All @@ -1614,6 +1615,7 @@ typedef MXHTTPOperation* (^MXRestClientIdentityServerAccessTokenHandler)(void (^
*/
- (MXHTTPOperation*)add3PIDOnlyWithSessionId:(NSString*)sid
clientSecret:(NSString*)clientSecret
authParams:(NSDictionary*)authParameters
success:(void (^)(void))success
failure:(void (^)(NSError *error))failure NS_REFINED_FOR_SWIFT;

Expand Down
10 changes: 8 additions & 2 deletions MatrixSDK/MXRestClient.m
Original file line number Diff line number Diff line change
Expand Up @@ -2991,15 +2991,21 @@ - (MXHTTPOperation*)add3PID:(NSString*)sid

- (MXHTTPOperation*)add3PIDOnlyWithSessionId:(NSString*)sid
clientSecret:(NSString*)clientSecret
authParams:(NSDictionary*)authParameters
success:(void (^)(void))success
failure:(void (^)(NSError *error))failure
{
NSString *path = [NSString stringWithFormat:@"%@/account/3pid/add", kMXAPIPrefixPathUnstable];

NSDictionary *parameters = @{
NSMutableDictionary *parameters = [@{
@"sid": sid,
@"client_secret": clientSecret
};
} mutableCopy];

if (authParameters)
{
parameters[@"auth"] = authParameters;
}

MXWeakify(self);
return [httpClient requestWithMethod:@"POST"
Expand Down
35 changes: 35 additions & 0 deletions MatrixSDK/ThreePidAdd/MX3PidAddManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,20 @@ NS_ERROR_ENUM(MX3PidAddManagerErrorDomain)
- (void)cancel3PidAddSession:(MX3PidAddSession*)threePidAddSession NS_REFINED_FOR_SWIFT;


#pragma mark - Add 3rd-Party Identifier

/**
Get the authentication flow required to add a 3rd party id to the user homeserver account.
@param success A block object called when the operation succeeds. If the returned flows is nil, no auth is required.
@param failure A block object called when the operation fails.
@return a MXHTTPOperation instance.
*/
- (MXHTTPOperation*)authenticationFlowForAdd3PidWithSuccess:(void (^)(NSArray<MXLoginFlow*> * _Nullable flows))success
failure:(void (^)(NSError * _Nonnull))failure;


#pragma mark - Add Email

/**
Expand Down Expand Up @@ -95,6 +109,15 @@ NS_ERROR_ENUM(MX3PidAddManagerErrorDomain)
success:(void (^)(void))success
failure:(void (^)(NSError * _Nonnull))failure NS_REFINED_FOR_SWIFT;

- (void)tryFinaliseAddEmailSession:(MX3PidAddSession*)threePidAddSession
withPassword:(nullable NSString*)password
success:(void (^)(void))success
failure:(void (^)(NSError * _Nonnull))failure NS_REFINED_FOR_SWIFT;

- (void)tryFinaliseAddEmailSession:(MX3PidAddSession*)threePidAddSession
authParams:(nullable NSDictionary*)authParams
success:(void (^)(void))success
failure:(void (^)(NSError * _Nonnull))failure NS_REFINED_FOR_SWIFT;

#pragma mark - Add MSISDN

Expand Down Expand Up @@ -131,6 +154,18 @@ NS_ERROR_ENUM(MX3PidAddManagerErrorDomain)
success:(void (^)(void))success
failure:(void (^)(NSError * _Nonnull))failure NS_REFINED_FOR_SWIFT;

- (void)finaliseAddPhoneNumberSession:(MX3PidAddSession*)threePidAddSession
withToken:(NSString*)token
password:(nullable NSString*)password
success:(void (^)(void))success
failure:(void (^)(NSError * _Nonnull))failure NS_REFINED_FOR_SWIFT;

- (void)finaliseAddPhoneNumberSession:(MX3PidAddSession*)threePidAddSession
withToken:(NSString*)token
authParams:(nullable NSDictionary*)authParams
success:(void (^)(void))success
failure:(void (^)(NSError * _Nonnull))failure NS_REFINED_FOR_SWIFT;


#pragma mark - Bind Email

Expand Down
149 changes: 147 additions & 2 deletions MatrixSDK/ThreePidAdd/MX3PidAddManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,50 @@ - (void)cancel3PidAddSession:(MX3PidAddSession*)threePidAddSession
}



#pragma mark - Add 3rd-Party Identifier

- (MXHTTPOperation*)authenticationFlowForAdd3PidWithSuccess:(void (^)(NSArray<MXLoginFlow*> * _Nullable flows))success
failure:(void (^)(NSError * _Nonnull))failure
{
// Trigger a random request to the API
// If authentication is required, it will provide the flow in the error response
return [self->mxSession.matrixRestClient add3PIDOnlyWithSessionId:@"" clientSecret:@"" authParams:nil success:^{
// This should not happen
success(nil);
} failure:^(NSError *error) {
NSHTTPURLResponse *urlResponse = [MXHTTPOperation urlResponseFromError:error];
if (urlResponse)
{
switch (urlResponse.statusCode)
{
case 400:
// No required authentication
success(nil);
break;

case 401:
{
// Extract authentication flows
MXAuthenticationSession *authSession;
MXJSONModelSetMXJSONModel(authSession, MXAuthenticationSession, error.userInfo[MXHTTPClientErrorResponseDataKey]);
success(authSession.flows);
break;
}

default:
failure(error);
break;
}
}
else
{
failure(error);
}
}];
}


#pragma mark - Add Email

- (MX3PidAddSession*)startAddEmailSessionWithEmail:(NSString*)email
Expand Down Expand Up @@ -94,6 +138,37 @@ - (MX3PidAddSession*)startAddEmailSessionWithEmail:(NSString*)email
- (void)tryFinaliseAddEmailSession:(MX3PidAddSession*)threePidAddSession
success:(void (^)(void))success
failure:(void (^)(NSError * _Nonnull))failure
{
[self tryFinaliseAddEmailSession:threePidAddSession authParams:nil success:success failure:failure];
}

- (void)tryFinaliseAddEmailSession:(MX3PidAddSession*)threePidAddSession
withPassword:(nullable NSString*)password
success:(void (^)(void))success
failure:(void (^)(NSError * _Nonnull))failure
{
// Make a first request to start user-interactive authentication
MXWeakify(self);
[self tryFinaliseAddEmailSession:threePidAddSession authParams:nil success:success failure:^(NSError * _Nonnull error) {
MXStrongifyAndReturnIfNil(self);

NSDictionary *authParams = [self authParamsFromError:error andPassword:password];
if (authParams)
{
// Retry but authenticated
[self tryFinaliseAddEmailSession:threePidAddSession authParams:authParams success:success failure:failure];
}
else
{
failure(error);
}
}];
}

- (void)tryFinaliseAddEmailSession:(MX3PidAddSession*)threePidAddSession
authParams:(nullable NSDictionary*)authParams
success:(void (^)(void))success
failure:(void (^)(NSError * _Nonnull))failure
{
NSLog(@"[MX3PidAddManager] tryFinaliseAddEmailSession: threePid: %@", threePidAddSession);

Expand All @@ -111,7 +186,7 @@ - (void)tryFinaliseAddEmailSession:(MX3PidAddSession*)threePidAddSession
if (doesServerSupportSeparateAddAndBind)
{
// https://gist.github.com/jryans/839a09bf0c5a70e2f36ed990d50ed928#2b-adding-a-3pid-to-hs-account-after-registration-post-msc2290
threePidAddSession.httpOperation = [mxSession.matrixRestClient add3PIDOnlyWithSessionId:threePidAddSession.sid clientSecret:threePidAddSession.clientSecret success:^{
threePidAddSession.httpOperation = [mxSession.matrixRestClient add3PIDOnlyWithSessionId:threePidAddSession.sid clientSecret:threePidAddSession.clientSecret authParams:authParams success:^{

NSLog(@"[MX3PidAddManager] tryFinaliseAddEmailSession: DONE: threePid: %@", threePidAddSession);

Expand Down Expand Up @@ -187,6 +262,39 @@ - (void)finaliseAddPhoneNumberSession:(MX3PidAddSession*)threePidAddSession
withToken:(NSString*)token
success:(void (^)(void))success
failure:(void (^)(NSError * _Nonnull))failure
{
[self finaliseAddPhoneNumberSession:threePidAddSession withToken:token authParams:nil success:success failure:failure];
}

- (void)finaliseAddPhoneNumberSession:(MX3PidAddSession*)threePidAddSession
withToken:(NSString*)token
password:(nullable NSString*)password
success:(void (^)(void))success
failure:(void (^)(NSError * _Nonnull))failure
{
// Make a first request to start user-interactive authentication
MXWeakify(self);
[self finaliseAddPhoneNumberSession:threePidAddSession withToken:token authParams:nil success:success failure:^(NSError * _Nonnull error) {
MXStrongifyAndReturnIfNil(self);

NSDictionary *authParams = [self authParamsFromError:error andPassword:password];
if (authParams)
{
// Retry but authenticated
[self finaliseAddPhoneNumberSession:threePidAddSession withToken:token authParams:authParams success:success failure:failure];
}
else
{
failure(error);
}
}];
}

- (void)finaliseAddPhoneNumberSession:(MX3PidAddSession*)threePidAddSession
withToken:(NSString*)token
authParams:(nullable NSDictionary*)authParams
success:(void (^)(void))success
failure:(void (^)(NSError * _Nonnull))failure
{
NSLog(@"[MX3PidAddManager] finaliseAddPhoneNumberSession: threePid: %@", threePidAddSession);

Expand All @@ -209,7 +317,7 @@ - (void)finaliseAddPhoneNumberSession:(MX3PidAddSession*)threePidAddSession
if (self->doesServerSupportSeparateAddAndBind)
{
// https://gist.github.com/jryans/839a09bf0c5a70e2f36ed990d50ed928#2b-adding-a-3pid-to-hs-account-after-registration-post-msc2290
operation = [self->mxSession.matrixRestClient add3PIDOnlyWithSessionId:threePidAddSession.sid clientSecret:threePidAddSession.clientSecret success:^{
operation = [self->mxSession.matrixRestClient add3PIDOnlyWithSessionId:threePidAddSession.sid clientSecret:threePidAddSession.clientSecret authParams:authParams success:^{

NSLog(@"[MX3PidAddManager] finaliseAddPhoneNumberSession: DONE: threePid: %@", threePidAddSession);

Expand Down Expand Up @@ -483,6 +591,43 @@ - (MXHTTPOperation *)submitMsisdnTokenOtherUrl:(NSString *)url
failure:failure];
}

/**
Build auth params when User-Interactive Authentication is required.
The supported auth flow is "m.login.password".
@param error the error got from the API request.
@param password the password to use.
@return the params to make an authenticated API request.
*/
- (NSDictionary*)authParamsFromError:(NSError*)error andPassword:(NSString*)password
{
NSDictionary *authParams;
NSHTTPURLResponse *urlResponse = [MXHTTPOperation urlResponseFromError:error];

if (urlResponse && urlResponse.statusCode == 401)
{

MXAuthenticationSession *authSession;
MXJSONModelSetMXJSONModel(authSession, MXAuthenticationSession, error.userInfo[MXHTTPClientErrorResponseDataKey]);
if (authSession && password)
{
NSString *userId = self->mxSession.matrixRestClient.credentials.userId;
authParams = @{
@"type": kMXLoginFlowTypePassword,
@"identifier": @{
@"type": kMXLoginIdentifierTypeUser,
@"user": userId
},
@"password": password,
@"user": userId
};
}
}

return authParams;
}


#pragma mark - Bind to Identity Server -

Expand Down
2 changes: 1 addition & 1 deletion MatrixSDK/Utils/MXHTTPClient.m
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
*/
#define MXHTTPCLIENT_RETRY_JITTER_MS 3000

NSString * const MXHTTPClientErrorResponseDataKey = @"com.matrixsdk.httpclient.error.response.data";
NSString* const MXHTTPClientErrorResponseDataKey = @"com.matrixsdk.httpclient.error.response.data";
NSString* const kMXHTTPClientUserConsentNotGivenErrorNotification = @"kMXHTTPClientUserConsentNotGivenErrorNotification";
NSString* const kMXHTTPClientUserConsentNotGivenErrorNotificationConsentURIKey = @"kMXHTTPClientUserConsentNotGivenErrorNotificationConsentURIKey";
NSString* const kMXHTTPClientMatrixErrorNotification = @"kMXHTTPClientMatrixErrorNotification";
Expand Down

0 comments on commit 9f77ce8

Please sign in to comment.