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

Support identity server v2 API #2684

Merged
merged 9 commits into from
Aug 30, 2019
4 changes: 4 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ Changes in 0.9.3 (2019-08-)

Improvements:
* Prompt to accept integration manager policies on use (#2600).
* Use MXIdentityService to perform identity server requests (#2647).
* Support identity server v2 API authentication (#2603).
* Use the hashed v2 lookup API for 3PIDs (#2652).
* Prompt to accept identity server policies on firt use (#2602).

Changes in 0.9.2 (2019-08-08)
===============================================
Expand Down
88 changes: 84 additions & 4 deletions Riot/AppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@
NSString *const kAppDelegateDidTapStatusBarNotification = @"kAppDelegateDidTapStatusBarNotification";
NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateNetworkStatusDidChangeNotification";

@interface AppDelegate () <PKPushRegistryDelegate, GDPRConsentViewControllerDelegate, DeviceVerificationCoordinatorBridgePresenterDelegate>
@interface AppDelegate () <PKPushRegistryDelegate, GDPRConsentViewControllerDelegate, DeviceVerificationCoordinatorBridgePresenterDelegate, ServiceTermsModalCoordinatorBridgePresenterDelegate>
{
/**
Reachability observer
Expand Down Expand Up @@ -233,6 +233,8 @@ The current call view controller (if any).
@property (weak, nonatomic) UIAlertController *gdprConsentNotGivenAlertController;
@property (weak, nonatomic) UIViewController *gdprConsentController;

@property (nonatomic, strong) ServiceTermsModalCoordinatorBridgePresenter *serviceTermsModalCoordinatorBridgePresenter;

/**
Used to manage on boarding steps, like create DM with riot bot
*/
Expand Down Expand Up @@ -647,6 +649,9 @@ - (void)applicationDidBecomeActive:(UIApplication *)application
// Register to GDPR consent not given notification
[self registerUserConsentNotGivenNotification];

// Register to identity server terms not signed notification
[self registerIdentityServiceTermsNotSignedNotification];

// Start monitoring reachability
[[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {

Expand Down Expand Up @@ -2101,19 +2106,37 @@ - (BOOL)handleUniversalLink:(NSUserActivity*)userActivity
// iOS Patch: fix vector.im urls before using it
webURL = [Tools fixURLWithSeveralHashKeys:webURL];

NSString *validateEmailSubmitTokenPath = @"validate/email/submitToken";

NSString *validateEmailSubmitTokenAPIPathV1 = [NSString stringWithFormat:@"/%@/%@", kMXIdentityAPIPrefixPathV1, validateEmailSubmitTokenPath];
NSString *validateEmailSubmitTokenAPIPathV2 = [NSString stringWithFormat:@"/%@/%@", kMXIdentityAPIPrefixPathV2, validateEmailSubmitTokenPath];

// Manage email validation link
if ([webURL.path isEqualToString:@"/_matrix/identity/api/v1/validate/email/submitToken"])
if ([webURL.path isEqualToString:validateEmailSubmitTokenAPIPathV1] || [webURL.path isEqualToString:validateEmailSubmitTokenAPIPathV2])
{
// Validate the email on the passed identity server
NSString *identityServer = [NSString stringWithFormat:@"%@://%@", webURL.scheme, webURL.host];
MXRestClient *identityRestClient = [[MXRestClient alloc] initWithHomeServer:identityServer andOnUnrecognizedCertificateBlock:nil];

MXSession *mainSession = self.mxSessions.firstObject;
MXRestClient *homeserverRestClient;

if (mainSession.matrixRestClient)
{
homeserverRestClient = mainSession.matrixRestClient;
}
else
{
homeserverRestClient = [[MXRestClient alloc] initWithHomeServer:identityServer andOnUnrecognizedCertificateBlock:nil];
}

MXIdentityService *identityService = [[MXIdentityService alloc] initWithIdentityServer:identityServer andHomeserverRestClient:homeserverRestClient];

// Extract required parameters from the link
NSArray<NSString*> *pathParams;
NSMutableDictionary *queryParams;
[self parseUniversalLinkFragment:webURL.absoluteString outPathParams:&pathParams outQueryParams:&queryParams];

[identityRestClient submit3PIDValidationToken:queryParams[@"token"] medium:kMX3PIDMediumEmail clientSecret:queryParams[@"client_secret"] sid:queryParams[@"sid"] success:^{
[identityService submit3PIDValidationToken:queryParams[@"token"] medium:kMX3PIDMediumEmail clientSecret:queryParams[@"client_secret"] sid:queryParams[@"sid"] success:^{

NSLog(@"[AppDelegate] handleUniversalLink. Email successfully validated.");

Expand Down Expand Up @@ -4626,6 +4649,63 @@ - (void)gdprConsentViewControllerDidConsentToGDPRWithSuccess:(GDPRConsentViewCon
}];
}

#pragma mark - Identity server service terms

// Observe identity server terms not signed notification
- (void)registerIdentityServiceTermsNotSignedNotification
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleIdentityServiceTermsNotSignedNotification:) name:MXIdentityServiceTermsNotSignedNotification object:nil];
}

- (void)handleIdentityServiceTermsNotSignedNotification:(NSNotification*)notification
{
NSString *baseURL;
NSString *accessToken;

MXJSONModelSetString(baseURL, notification.userInfo[MXIdentityServiceNotificationIdentityServerKey]);
MXJSONModelSetString(accessToken, notification.userInfo[MXIdentityServiceNotificationAccessTokenKey]);

[self presentIdentityServerTermsWithBaseURL:baseURL andAccessToken:accessToken];
}

- (void)presentIdentityServerTermsWithBaseURL:(NSString*)baseURL andAccessToken:(NSString*)accessToken
{
MXSession *mxSession = self.mxSessions.firstObject;

if (!mxSession || !baseURL || !accessToken || self.serviceTermsModalCoordinatorBridgePresenter.isPresenting)
{
return;
}

ServiceTermsModalCoordinatorBridgePresenter *serviceTermsModalCoordinatorBridgePresenter = [[ServiceTermsModalCoordinatorBridgePresenter alloc] initWithSession:mxSession
baseUrl:baseURL
serviceType:MXServiceTypeIdentityService
accessToken:accessToken];

serviceTermsModalCoordinatorBridgePresenter.delegate = self;

UIViewController *presentingViewController = self.window.rootViewController.presentedViewController ?: self.window.rootViewController;

[serviceTermsModalCoordinatorBridgePresenter presentFrom:presentingViewController animated:YES];
self.serviceTermsModalCoordinatorBridgePresenter = serviceTermsModalCoordinatorBridgePresenter;
}

- (void)serviceTermsModalCoordinatorBridgePresenterDelegateDidAccept:(ServiceTermsModalCoordinatorBridgePresenter * _Nonnull)coordinatorBridgePresenter
{
[coordinatorBridgePresenter dismissWithAnimated:YES completion:^{

}];
self.serviceTermsModalCoordinatorBridgePresenter = nil;
}

- (void)serviceTermsModalCoordinatorBridgePresenterDelegateDidCancel:(ServiceTermsModalCoordinatorBridgePresenter * _Nonnull)coordinatorBridgePresenter
{
[coordinatorBridgePresenter dismissWithAnimated:YES completion:^{

}];
self.serviceTermsModalCoordinatorBridgePresenter = nil;
}

#pragma mark - Settings

- (void)setupUserDefaults
Expand Down
6 changes: 3 additions & 3 deletions Riot/Generated/Strings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ internal enum VectorL10n {
internal static var authForgotPassword: String {
return VectorL10n.tr("Vector", "auth_forgot_password")
}
/// No Identity Server is configured: add one to reset your password.
/// No identity server is configured: add one to reset your password.
internal static var authForgotPasswordErrorNoConfiguredIdentityServer: String {
return VectorL10n.tr("Vector", "auth_forgot_password_error_no_configured_identity_server")
}
Expand Down Expand Up @@ -1502,7 +1502,7 @@ internal enum VectorL10n {
internal static var roomCreationAppearancePicture: String {
return VectorL10n.tr("Vector", "room_creation_appearance_picture")
}
/// No Identity Server is configured so you cannot add a participant with an email.
/// No identity server is configured so you cannot add a participant with an email.
internal static var roomCreationErrorInviteUserByEmailWithoutIdentityServer: String {
return VectorL10n.tr("Vector", "room_creation_error_invite_user_by_email_without_identity_server")
}
Expand Down Expand Up @@ -2126,7 +2126,7 @@ internal enum VectorL10n {
internal static var roomParticipantsRemoveThirdPartyInviteMsg: String {
return VectorL10n.tr("Vector", "room_participants_remove_third_party_invite_msg")
}
/// No Identity Server is configured so you cannot start a chat with a contact using an email.
/// No identity server is configured so you cannot start a chat with a contact using an email.
internal static var roomParticipantsStartNewChatErrorUsingUserEmailWithoutIdentityServer: String {
return VectorL10n.tr("Vector", "room_participants_start_new_chat_error_using_user_email_without_identity_server")
}
Expand Down
45 changes: 28 additions & 17 deletions Riot/Modules/Authentication/Views/AuthInputsView.m
Original file line number Diff line number Diff line change
Expand Up @@ -604,20 +604,22 @@ - (void)prepareParameters:(void (^)(NSDictionary *parameters, NSError *error))ca
restClient = [self.delegate authInputsViewThirdPartyIdValidationRestClient:self];
}

if (restClient)
if (restClient && restClient.identityServer)
{
// Check whether a second 3pid is available
_isThirdPartyIdentifierPending = (nbPhoneNumber && ![self isFlowCompleted:kMXLoginFlowTypeMSISDN]);

// Launch email validation
submittedEmail = [[MXK3PID alloc] initWithMedium:kMX3PIDMediumEmail andAddress:self.emailTextField.text];

NSString *identityServer = restClient.identityServer;

// Create the next link that is common to all Vector.im clients
NSString *nextLink = [NSString stringWithFormat:@"%@/#/register?client_secret=%@&hs_url=%@&is_url=%@&session_id=%@",
[Tools webAppUrl],
[submittedEmail.clientSecret stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]],
[restClient.homeserver stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]],
[restClient.identityServer stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]],
[identityServer stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]],
[currentSession.session stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]]];

[submittedEmail requestValidationTokenWithMatrixRestClient:restClient
Expand All @@ -626,7 +628,7 @@ - (void)prepareParameters:(void (^)(NSDictionary *parameters, NSError *error))ca
success:^
{

NSURL *identServerURL = [NSURL URLWithString:restClient.identityServer];
NSURL *identServerURL = [NSURL URLWithString:identityServer];
NSDictionary *parameters;
parameters = @{
@"auth": @{@"session":currentSession.session, @"threepid_creds": @{@"client_secret": submittedEmail.clientSecret, @"id_server": identServerURL.host, @"sid": submittedEmail.sid}, @"type": kMXLoginFlowTypeEmailIdentity},
Expand Down Expand Up @@ -1646,25 +1648,34 @@ - (void)showValidationMSISDNDialogToPrepareParameters:(void (^)(NSDictionary *pa
{
[self->submittedMSISDN submitValidationToken:smsCode success:^{

// Retrieve the REST client from delegate
MXRestClient *restClient;
// Retrieve the identity service from delegate
MXIdentityService *identityService;

if (self.delegate && [self.delegate respondsToSelector:@selector(authInputsViewThirdPartyIdValidationRestClient:)])
if (self.delegate && [self.delegate respondsToSelector:@selector(authInputsViewThirdPartyIdValidationIdentityService:)])
{
restClient = [self.delegate authInputsViewThirdPartyIdValidationRestClient:self];
identityService = [self.delegate authInputsViewThirdPartyIdValidationIdentityService:self];
}

NSURL *identServerURL = [NSURL URLWithString:restClient.identityServer];
NSDictionary *parameters;
parameters = @{
@"auth": @{@"session":self->currentSession.session, @"threepid_creds": @{@"client_secret": self->submittedMSISDN.clientSecret, @"id_server": identServerURL.host, @"sid": self->submittedMSISDN.sid}, @"type": kMXLoginFlowTypeMSISDN},
@"username": self.userLoginTextField.text,
@"password": self.passWordTextField.text,
@"bind_msisdn": @(YES),
@"bind_email": @([self isFlowCompleted:kMXLoginFlowTypeEmailIdentity])
};
NSString *identityServer = identityService.identityServer;

callback(parameters, nil);
if (identityServer)
{
NSURL *identServerURL = [NSURL URLWithString:identityServer];
NSDictionary *parameters;
parameters = @{
@"auth": @{@"session":self->currentSession.session, @"threepid_creds": @{@"client_secret": self->submittedMSISDN.clientSecret, @"id_server": identServerURL.host, @"sid": self->submittedMSISDN.sid}, @"type": kMXLoginFlowTypeMSISDN},
@"username": self.userLoginTextField.text,
@"password": self.passWordTextField.text,
@"bind_msisdn": @(YES),
@"bind_email": @([self isFlowCompleted:kMXLoginFlowTypeEmailIdentity])
};

callback(parameters, nil);
}
else
{
NSLog(@"[AuthInputsView] Failed to retrieve identity server URL");
}

} failure:^(NSError *error) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ final class ServiceTermsModalCoordinatorBridgePresenter: NSObject {

weak var delegate: ServiceTermsModalCoordinatorBridgePresenterDelegate?

var isPresenting: Bool {
return self.coordinator != nil
}

// MARK: - Setup

init(session: MXSession, baseUrl: String, serviceType: MXServiceType, accessToken: String) {
Expand Down