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

Modified Ui Authentication #135

Merged
merged 33 commits into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
a51d1fb
Resolve conflicts after rebase
BichraiX Jul 23, 2024
c73a126
feat : Updated Ui Authentication. Added a readme to clarify usage. mo…
BichraiX Jul 25, 2024
b33ef15
chore : prettier
BichraiX Jul 25, 2024
0329bb9
Merge branch 'full-id-service' into client-server-ui-auth-register
BichraiX Jul 25, 2024
cc05102
feat : refactored the code for /register and added tests
BichraiX Jul 25, 2024
bbc121e
chore : prettier
BichraiX Jul 25, 2024
3c2d212
feat : added function to get allowedFlows from the config for the reg…
BichraiX Jul 26, 2024
74e3831
chore : prettier
BichraiX Jul 26, 2024
2d2a9f7
feat : corrected toMatrixId function to comply with the spec. Added h…
BichraiX Jul 26, 2024
2d9d18d
chore : prettier
BichraiX Jul 26, 2024
dd4ae01
finalized UiAuth and register
BichraiX Aug 12, 2024
2bc3ede
feat : added length checking in addition to regex
h1ppox99 Jul 25, 2024
9f9ae6f
fix : fixed type syntax
h1ppox99 Jul 25, 2024
d8e8324
feat : added tests for regex
h1ppox99 Jul 25, 2024
227d066
feat: added getcapabilities endpoint
Mathixx Aug 8, 2024
0b03293
feat: added capability checks in profiles related endpoints // ensure…
Mathixx Aug 8, 2024
8e2140b
Decrease log level
guimard Aug 8, 2024
6b3b85f
Fix test
guimard Aug 9, 2024
69bdf7f
feat: added version API
Mathixx Aug 9, 2024
a9022c6
feat: added versions endpoint and updated the capabilities one with n…
Mathixx Aug 9, 2024
c245bc4
Fix some istanbul hooks
guimard Aug 9, 2024
6adaafa
Resolve conflicts after rebase
BichraiX Jul 23, 2024
bc06840
feat : Updated Ui Authentication. Added a readme to clarify usage. mo…
BichraiX Jul 25, 2024
e9ef8c3
feat : refactored the code for /register and added tests
BichraiX Jul 25, 2024
d4b7e78
feat : added function to get allowedFlows from the config for the reg…
BichraiX Jul 26, 2024
e630767
chore : prettier
BichraiX Aug 12, 2024
3e6ba47
fix : merge mistake
BichraiX Aug 12, 2024
f3060f0
fix : merge mistakes
BichraiX Aug 12, 2024
f8da622
Merge branch 'full-id-service' into client-server-ui-auth-register
BichraiX Aug 12, 2024
5da008b
fix : incorrect config file in login tests
BichraiX Aug 12, 2024
2314777
fix : removed useless token in db setup
BichraiX Aug 12, 2024
50eb7d6
fix : moved setupTokens to testData
BichraiX Aug 12, 2024
4868a18
fix : path to setupTokens in test file
BichraiX Aug 12, 2024
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
3 changes: 3 additions & 0 deletions packages/matrix-client-server/src/__testData__/buildUserDB.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ const matrixDbQueries = [
'CREATE TABLE IF NOT EXISTS "access_tokens" (id BIGINT PRIMARY KEY, user_id TEXT NOT NULL, device_id TEXT, token TEXT NOT NULL,valid_until_ms BIGINT,puppets_user_id TEXT,last_validated BIGINT, refresh_token_id BIGINT REFERENCES refresh_tokens (id) ON DELETE CASCADE, used BOOLEAN,UNIQUE(token))',
'CREATE TABLE IF NOT EXISTS refresh_tokens (id BIGINT PRIMARY KEY,user_id TEXT NOT NULL,device_id TEXT NOT NULL,token TEXT NOT NULL,next_token_id BIGINT REFERENCES refresh_tokens (id) ON DELETE CASCADE, expiry_ts BIGINT DEFAULT NULL, ultimate_session_expiry_ts BIGINT DEFAULT NULL,UNIQUE(token))',
'CREATE TABLE IF NOT EXISTS "user_filters" ( user_id TEXT NOT NULL, filter_id BIGINT NOT NULL, filter_json BYTEA NOT NULL )',
'CREATE TABLE ui_auth_sessions(session_id TEXT NOT NULL,creation_time BIGINT NOT NULL, serverdict TEXT NOT NULL, clientdict TEXT NOT NULL,uri TEXT NOT NULL, method TEXT NOT NULL, description TEXT NOT NULL, UNIQUE (session_id))',
'CREATE TABLE ui_auth_sessions_credentials(session_id TEXT NOT NULL, stage_type TEXT NOT NULL, result TEXT NOT NULL, UNIQUE (session_id, stage_type),FOREIGN KEY (session_id) REFERENCES ui_auth_sessions (session_id))',
'CREATE TABLE ui_auth_sessions_ips(session_id TEXT NOT NULL,ip TEXT NOT NULL,user_agent TEXT NOT NULL,UNIQUE (session_id, ip, user_agent), FOREIGN KEY (session_id)REFERENCES ui_auth_sessions (session_id))',
'CREATE TABLE IF NOT EXISTS current_state_events (event_id text NOT NULL,room_id text NOT NULL,type text NOT NULL,state_key text NOT NULL,membership text)'
]

Expand Down
279 changes: 174 additions & 105 deletions packages/matrix-client-server/src/account/3pid/3pid.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ import { buildMatrixDb, buildUserDB } from '../../__testData__/buildUserDB'
import { type Config } from '../../types'
import defaultConfig from '../../__testData__/3pidConf.json'
import { getLogger, type TwakeLogger } from '@twake/logger'
import { setupTokens, validToken } from '../../utils/setupTokens'
import e from 'express'
import { setupTokens, validToken, validToken2 } from '../../utils/setupTokens'

process.env.TWAKE_CLIENT_SERVER_CONF = './src/__testData__/3pidConf.json'
jest.mock('node-fetch', () => jest.fn())
Expand Down Expand Up @@ -112,42 +111,145 @@ describe('Use configuration file', () => {
await setupTokens(clientServer, logger)
})
describe('/_matrix/client/v3/account/3pid/add', () => {
let session: string
describe('User Interactive Authentication', () => {
it('should refuse to validate a userId that does not match the regex', async () => {
const response = await request(app)
.post('/_matrix/client/v3/account/3pid/add')
.set('Accept', 'application/json')
.set('Authorization', `Bearer wrongUserAccessToken`)
.send({
sid: 'sid',
client_secret: 'cs'
})
console.log(response.body)
expect(response.statusCode).toBe(400)
expect(response.body).toHaveProperty('errcode', 'M_INVALID_PARAM')
expect(response.body).toHaveProperty('error', 'Invalid user ID')
})
it('should refuse to authenticate a user with a password if he does not have one registered', async () => {
const response = await request(app)
.post('/_matrix/client/v3/account/3pid/add')
.set('Accept', 'application/json')
.set('Authorization', `Bearer ${validToken2}`)
.send({
sid: 'sid',
client_secret: 'cs'
})
expect(response.statusCode).toBe(401)
session = response.body.session
const response1 = await request(app)
.post('/_matrix/client/v3/account/3pid/add')
.set('Accept', 'application/json')
.set('Authorization', `Bearer ${validToken2}`)
.send({
sid: 'sid',
client_secret: 'cs',
auth: {
type: 'm.login.password',
session,
password: 'password',
identifier: {
type: 'm.id.user',
user: '@testuser2:example.com'
}
}
})
expect(response1.statusCode).toBe(401)
expect(response1.body).toHaveProperty('errcode', 'M_FORBIDDEN')
expect(response1.body).toHaveProperty(
'error',
'The user does not have a password registered'
)
})
})
let sid: string
let token: string
it('should refuse an invalid secret', async () => {
const response1 = await request(app)
.post('/_matrix/client/v3/account/3pid/add')
.set('Accept', 'application/json')
.set('Authorization', `Bearer ${validToken}`)
.send({
sid: 'sid',
client_secret: 'my'
})
expect(response1.statusCode).toBe(401)
session = response1.body.session
const response = await request(app)
.post('/_matrix/client/v3/account/3pid/add')
.set('Accept', 'application/json')
.set('Authorization', `Bearer ${validToken}`)
.send({
sid: 'sid',
client_secret: 'my',
auth: { type: 'm.login.dummy', session: 'authSession' }
auth: {
type: 'm.login.password',
session,
password:
'$2a$10$zQJv3V3Kjw7Jq7Ww1X7z5e1QXsVd1m3JdV9vG6t8Jv7jQz4Z5J1QK',
identifier: { type: 'm.id.user', user: '@testuser:example.com' }
}
})
expect(response.statusCode).toBe(400)
expect(response.body).toHaveProperty('errcode', 'M_INVALID_PARAM')
expect(response.body).toHaveProperty('error', 'Invalid client_secret')
})
it('should refuse an invalid session ID', async () => {
const response1 = await request(app)
.post('/_matrix/client/v3/account/3pid/add')
.set('Accept', 'application/json')
.set('Authorization', `Bearer ${validToken}`)
.send({
sid: 'sid',
client_secret: 'my'
})
expect(response1.statusCode).toBe(401)
session = response1.body.session
const response = await request(app)
.post('/_matrix/client/v3/account/3pid/add')
.set('Accept', 'application/json')
.set('Authorization', `Bearer ${validToken}`)
.send({
sid: '$!:',
sid: '$;!',
client_secret: 'mysecret',
auth: { type: 'm.login.dummy', session: 'authSession2' }
auth: {
type: 'm.login.password',
session,
password:
'$2a$10$zQJv3V3Kjw7Jq7Ww1X7z5e1QXsVd1m3JdV9vG6t8Jv7jQz4Z5J1QK',
identifier: { type: 'm.id.user', user: '@testuser:example.com' }
}
})
expect(response.statusCode).toBe(400)
expect(response.body).toHaveProperty('errcode', 'M_INVALID_PARAM')
expect(response.body).toHaveProperty('error', 'Invalid session ID')
})
it('should return 400 for a wrong combination of client secret and session ID', async () => {
const response1 = await request(app)
.post('/_matrix/client/v3/account/3pid/add')
.set('Accept', 'application/json')
.set('Authorization', `Bearer ${validToken}`)
.send({
sid: 'sid',
client_secret: 'my'
})
expect(response1.statusCode).toBe(401)
session = response1.body.session
const response = await request(app)
.post('/_matrix/client/v3/account/3pid/add')
.set('Accept', 'application/json')
.set('Authorization', `Bearer ${validToken}`)
.send({
sid: 'wrongSid',
client_secret: 'mysecret',
auth: { type: 'm.login.dummy', session: 'authSession3' }
auth: {
type: 'm.login.password',
session,
password:
'$2a$10$zQJv3V3Kjw7Jq7Ww1X7z5e1QXsVd1m3JdV9vG6t8Jv7jQz4Z5J1QK',
identifier: { type: 'm.id.user', user: '@testuser:example.com' }
}
})
expect(response.statusCode).toBe(400)
expect(response.body).toHaveProperty('errcode', 'M_NO_VALID_SESSION')
Expand All @@ -169,13 +271,30 @@ describe('Use configuration file', () => {
)
token = RegExp.$1
sid = RegExp.$2
const response1 = await request(app)
.post('/_matrix/client/v3/account/3pid/add')
.set('Accept', 'application/json')
.set('Authorization', `Bearer ${validToken}`)
.send({
sid: 'sid',
client_secret: 'my'
})
expect(response1.statusCode).toBe(401)
session = response1.body.session
const response = await request(app)
.post('/_matrix/client/v3/account/3pid/add')
.set('Accept', 'application/json')
.set('Authorization', `Bearer ${validToken}`)
.send({
sid,
client_secret: 'mysecret',
auth: { type: 'm.login.dummy', session: 'authSession4' }
auth: {
type: 'm.login.password',
session,
password:
'$2a$10$zQJv3V3Kjw7Jq7Ww1X7z5e1QXsVd1m3JdV9vG6t8Jv7jQz4Z5J1QK',
identifier: { type: 'm.id.user', user: '@testuser:example.com' }
}
})
expect(response.statusCode).toBe(400)
expect(response.body).toHaveProperty(
Expand All @@ -193,133 +312,83 @@ describe('Use configuration file', () => {
})
.set('Accept', 'application/json')
expect(submitTokenResponse.statusCode).toBe(200)
const response = await request(app)
.post('/_matrix/client/v3/account/3pid/add')
.set('Accept', 'application/json')
.send({
sid,
client_secret: 'mysecret',
auth: {
type: 'm.login.email.identity',
session: 'validatedSession',
threepid_creds: {
sid: 'validatedSession',
client_secret: 'validatedSecret'
}
}
})
expect(response.statusCode).toBe(200)
})
it('should refuse adding a 3pid already associated to another user', async () => {
const response = await request(app)
.post('/_matrix/client/v3/account/3pid/add')
.set('Accept', 'application/json')
.send({
sid,
client_secret: 'mysecret',
auth: {
type: 'm.login.email.identity',
session: 'newsession',
threepid_creds: {
sid: 'validatedSession',
client_secret: 'validatedSecret'
}
}
})
expect(response.statusCode).toBe(400)
expect(response.body).toHaveProperty('errcode', 'M_THREEPID_IN_USE')
})
it('should refuse authenticating a user with an unknown 3pid for UI Auth', async () => {
const response = await request(app)
const response1 = await request(app)
.post('/_matrix/client/v3/account/3pid/add')
.set('Accept', 'application/json')
.set('Authorization', `Bearer ${validToken}`)
.send({
sid: 'sid',
client_secret: 'mysecret',
auth: {
type: 'm.login.msisdn',
session: 'authSession7',
threepid_creds: { sid: 'sid', client_secret: 'mysecret' } // Unknown 3pid
}
})
expect(response.statusCode).toBe(401)
expect(response.body).toHaveProperty('errcode', 'M_NO_VALID_SESSION')
})
it('should refuse authenticating a user whose session has not been validated', async () => {
const requestTokenResponse = await request(app)
.post('/_matrix/client/v3/register/msisdn/requestToken')
.set('Accept', 'application/json')
.send({
client_secret: 'secret',
country: 'FR',
phone_number: '000000000',
next_link: 'http://localhost:8090',
send_attempt: 1
client_secret: 'my'
})
expect(requestTokenResponse.statusCode).toBe(200)
expect(sendSMSMock.mock.calls[0][0].raw).toMatch(
/token=([a-zA-Z0-9]{64})&client_secret=secret&sid=([a-zA-Z0-9]{64})/
)
token = RegExp.$1
sid = RegExp.$2
expect(response1.statusCode).toBe(401)
session = response1.body.session
const response = await request(app)
.post('/_matrix/client/v3/account/3pid/add')
.set('Accept', 'application/json')
.set('Authorization', `Bearer ${validToken}`)
.send({
sid: 'sid',
sid,
client_secret: 'mysecret',
auth: {
type: 'm.login.msisdn',
session: 'authSession8',
threepid_creds: { sid, client_secret: 'secret' }
type: 'm.login.password',
session,
password:
'$2a$10$zQJv3V3Kjw7Jq7Ww1X7z5e1QXsVd1m3JdV9vG6t8Jv7jQz4Z5J1QK',
identifier: { type: 'm.id.user', user: '@testuser:example.com' }
}
})
expect(response.statusCode).toBe(401)
expect(response.body).toHaveProperty(
'errcode',
'M_SESSION_NOT_VALIDATED'
)
expect(response.statusCode).toBe(200)
})
it('should refuse authenticating a user with an email that has not been added to a matrix userId', async () => {
const submitTokenResponse = await request(app)
.post('/_matrix/client/v3/register/email/submitToken')
.send({
token,
client_secret: 'secret',
sid
})
.set('Accept', 'application/json')
expect(submitTokenResponse.statusCode).toBe(200)
const response = await request(app)
it('should refuse adding a 3pid already associated to another user', async () => {
const response1 = await request(app)
.post('/_matrix/client/v3/account/3pid/add')
.set('Accept', 'application/json')
.set('Authorization', `Bearer ${validToken}`)
.send({
sid: 'sid',
client_secret: 'mysecret',
auth: {
type: 'm.login.msisdn',
session: 'authSession8',
threepid_creds: { sid, client_secret: 'secret' } // Unknown 3pid
}
client_secret: 'my'
})
expect(response.statusCode).toBe(401)
expect(response.body).toHaveProperty('errcode', 'M_THREEPID_NOT_FOUND')
})
it('should refuse adding a userId that is not of the right format', async () => {
expect(response1.statusCode).toBe(401)
session = response1.body.session
const response = await request(app)
.post('/_matrix/client/v3/account/3pid/add')
.set('Accept', 'application/json')
.set('Authorization', `Bearer ${validToken}`)
.send({
sid,
client_secret: 'secret',
client_secret: 'mysecret',
auth: {
type: 'm.login.dummy', // what happens when the Ui Auth is validated with a Dummy auth as the last stage, the userId is set to '' which is wrong
session: 'authSession5'
type: 'm.login.password',
session,
password:
'$2a$10$zQJv3V3Kjw7Jq7Ww1X7z5e1QXsVd1m3JdV9vG6t8Jv7jQz4Z5J1QK',
identifier: { type: 'm.id.user', user: '@testuser:example.com' }
}
})
expect(response.statusCode).toBe(400)
expect(response.body).toHaveProperty('errcode', 'M_INVALID_PARAM')
expect(response.body).toHaveProperty('errcode', 'M_THREEPID_IN_USE')
})

// Used to work but not anymore since we only check UI Auth with m.login.password or m.login.sso
// it('should refuse adding a userId that is not of the right format', async () => {
// const response = await request(app)
// .post('/_matrix/client/v3/account/3pid/add')
// .set('Accept', 'application/json')
// .set('Authorization', `Bearer ${validToken}`)
// .send({
// sid,
// client_secret: 'mysecret',
// auth: {
// type: 'm.login.password',
// session: 'authSession7',
// password:
// '$2a$10$zQJv3V3Kjw7Jq7Ww1X7z5e1QXsVd1m3JdV9vG6t8Jv7jQz4Z5J1QK',
// identifier: { type: 'm.id.user', user: '@testuser:example.com' }
// }
// })
// expect(response.statusCode).toBe(400)
// expect(response.body).toHaveProperty('errcode', 'M_INVALID_PARAM')
// })
})
describe('3PID Bind Endpoint', () => {
it('should return 200 on a successful bind', async () => {
Expand Down
Loading
Loading