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

Can register using an email address via identity server #1034

Closed
wants to merge 11 commits into from
11 changes: 10 additions & 1 deletion lib/SyTest/Homeserver/Dendrite.pm
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,9 @@ sub _get_config
global => {
server_name => $self->server_name,
private_key => $self->{paths}{matrix_key},

trusted_third_party_id_servers => [
"localhost:34586",
],
kafka => {
use_naffka => $JSON::true,
naffka_database => {
Expand Down Expand Up @@ -130,6 +132,13 @@ sub _get_config
},

client_api => {
custom_ca_path => "/sytest/keys/tls-selfsigned.crt",
registration => {
flows => [
{ stages => [ "m.login.email.identity" ]},
{ stages => [ "m.login.dummy" ]},
],
},
database => {
connection_string =>
( ! defined $ENV{'POSTGRES'} || $ENV{'POSTGRES'} == '0') ?
Expand Down
1 change: 1 addition & 0 deletions run-tests.pl
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
binmode(STDOUT, ":utf8");

our $BIND_HOST = "localhost";
our $ID_SERVER_PORT = 34586;
Copy link
Member

Choose a reason for hiding this comment

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

Why do we now need to set an explicit port ooi?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So that it can be added to trusted servers in homeserver configuration. I suppose that each time id_server_fixture is called random port is assigned.

Copy link
Member

Choose a reason for hiding this comment

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

Oh yes, I'm blind. We don't need it for Synapse because there's an option to trust all ID servers, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is quite messy in Synapse. For example in /register/email/requestToken id_server field will be just ignored. I could not figure out how does it work in user-interactive authentication. I didn't either found option to trust all ID servers in Synapse.


# a unique ID for this test run. It is used in some tests to create user IDs
# and the like.
Expand Down
4 changes: 2 additions & 2 deletions tests/07id-server.pl
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ sub id_server_fixture
$loop->add( $id_server );

$id_server->listen(
host => $BIND_HOST,
service => "",
host => "$BIND_HOST",
service => $ID_SERVER_PORT,
extensions => [qw( SSL )],
# Synapse currently only talks IPv4
family => "inet",
Expand Down
127 changes: 126 additions & 1 deletion tests/11register.pl
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,57 @@ sub validate_email {
}
push our @EXPORT, qw( validate_email );


=head2 validate_email_on_id_server

validate_email_on_id_server(
$http, $address,
id_server => $id_server,
path => "/r0/account/3pid/email/requestToken",
)->then( sub {
my ( $sid, $client_secret ) = @_;
});

Runs through a `.../requestToken` flow specified by $path for verifying that an email address
belongs to the user. Doesn't add the address to the account. It does not submit token as
validate_email does, but expects that mock identity server will validate email immediately.

Returns the session id and client secret which can then be used for binding the address.

=cut

sub validate_email_on_id_server {
my ( $http, $address, %params ) = @_;

my $client_secret = gen_client_secret();
my $sid;

return Future->needs_all(
await_id_validation_email( $params{id_server}, $address),

$http->do_request_json(
method => "POST",
uri => $params{path},
content => {
client_secret => $client_secret,
email => $address,
send_attempt => 1,
id_server => $params{id_server}->name,
id_access_token => $params{id_server}->get_access_token(),
},
)->then( sub {
my ( $resp ) = @_;
log_if_fail "requestToken response", $resp;

$sid = $resp->{sid};
Future->done;
}),
)->then( sub {
Future->done( $sid, $client_secret );
});
}
push our @EXPORT, qw( validate_email_on_id_server );

=head2 validate_msisdn

validate_msisdn(
Expand Down Expand Up @@ -164,7 +215,7 @@ sub await_id_validation_email {

log_if_fail "ID server email /requestToken request", $body;
assert_eq( $body->{email}, $address );
my $sid = $id_server->validate_email( $address, $body->{client_secret} );
my $sid = $id_server->validate_identity("email", $address, $body->{client_secret} );
$req->respond_json({
sid => $sid,
});
Expand Down Expand Up @@ -698,3 +749,77 @@ sub add_email_for_user {
});
};

test "Can register using an email address via identity server",
requires => [ $main::API_CLIENTS[0], localpart_fixture(), id_server_fixture() ],

do => sub {
my ( $http, $localpart, $id_server ) = @_;

my $email_address = 'testemail@example.com';

$http->do_request_json(
method => "POST",
uri => "/r0/register",

content => {
username => $localpart,
password => "noobers3kr1t",
device_id => "xyzzy",
},
)->main::expect_http_401->then( sub {
my ( $response ) = @_;

my $body = decode_json $response->content;

assert_json_keys( $body, qw( session flows ));

log_if_fail "First /register body", $body;

# Check that one of the flows' stages contains an "m.login.email.identity" stage
my $has_flow;
foreach my $idx ( 0 .. $#{ $body->{flows} } ) {
my $flow = $body->{flows}[$idx];
my $stages = $flow->{stages} || [];

$has_flow++ if
@$stages == 1 && $stages->[0] eq "m.login.email.identity";
}

assert_eq( $has_flow, 1, "hasFlow" );

validate_email_on_id_server(
$http,
$email_address,
id_server => $id_server,
path => "/r0/register/email/requestToken",
)->then( sub {
my ( $sid_email, $client_secret ) = @_;

# attempt to register with the 3pid
$http->do_request_json(
method => "POST",
uri => "/r0/register",
content => {
auth => {
type => "m.login.email.identity",
session => $body->{session},
threepidCreds => {
sid => $sid_email,
client_secret => $client_secret,
id_server => $id_server->name,
id_access_token => "foobar",
},
},
username => $localpart,
password => "noobers3kr1t",
device_id => "xyzzy",
},
)
})
})->then( sub {
my ( $body ) = @_;

assert_json_keys( $body, qw( user_id home_server ) );
Future->done( 1 );
});
};