From 97096f619fec9b48cdb44335f6dfcedfe436be59 Mon Sep 17 00:00:00 2001 From: garrettmills Date: Sun, 18 Oct 2020 23:27:23 -0500 Subject: [PATCH] Make UID case-insensitive --- app/classes/oidc/CoreIDAdapter.js | 2 +- app/classes/saml/FlitterProfileMapper.js | 4 ++-- app/controllers/OpenID.controller.js | 2 +- app/controllers/api/v1/Auth.controller.js | 13 +++++++------ app/controllers/api/v1/LDAP.controller.js | 10 +++++----- app/controllers/saml/SAML.controller.js | 2 +- app/ldap/controllers/Users.controller.js | 6 +++--- app/models/auth/User.model.js | 10 +++++----- app/models/iam/Policy.model.js | 2 +- app/models/ldap/Client.model.js | 4 ++-- app/routing/middleware/SAMLUtility.middleware.js | 2 +- app/services/MFA.service.js | 2 +- app/services/Vue.service.js | 2 +- app/unit/OpenIDConnectUnit.js | 2 +- 14 files changed, 32 insertions(+), 31 deletions(-) diff --git a/app/classes/oidc/CoreIDAdapter.js b/app/classes/oidc/CoreIDAdapter.js index 63e0583..ec4eaa6 100644 --- a/app/classes/oidc/CoreIDAdapter.js +++ b/app/classes/oidc/CoreIDAdapter.js @@ -49,7 +49,7 @@ class CoreIDAdapter { async findByUid(uid) { const result = await this.coll().find( - { 'payload.uid': uid }, + { 'payload.uid': uid.toLowerCase() }, { payload: 1 }, ).limit(1).next() diff --git a/app/classes/saml/FlitterProfileMapper.js b/app/classes/saml/FlitterProfileMapper.js index c411396..8829269 100644 --- a/app/classes/saml/FlitterProfileMapper.js +++ b/app/classes/saml/FlitterProfileMapper.js @@ -43,7 +43,7 @@ class FlitterProfileMapper { getClaims() { const claims = {} - claims[this.map.nameIdentifier] = this.user.uid + claims[this.map.nameIdentifier] = this.user.uid.toLowerCase() claims[this.map.email] = this.user.email claims[this.map.name] = `${this.user.first_name} ${this.user.last_name}` claims[this.map.givenname] = this.user.first_name @@ -54,7 +54,7 @@ class FlitterProfileMapper { } getNameIdentifier() { - return { nameIdentifier: this.user.uid } + return { nameIdentifier: this.user.uid.toLowerCase() } } } diff --git a/app/controllers/OpenID.controller.js b/app/controllers/OpenID.controller.js index 408dd3d..8135e3a 100644 --- a/app/controllers/OpenID.controller.js +++ b/app/controllers/OpenID.controller.js @@ -126,7 +126,7 @@ class OpenIDController extends Controller { return this.fail(res, 'Sorry, something has gone wrong.') } - return this[name](req, res, { uid, prompt, params, session }) + return this[name](req, res, { uid: uid.toLowerCase(), prompt, params, session }) } async consent(req, res, { uid, prompt, params, session }) { diff --git a/app/controllers/api/v1/Auth.controller.js b/app/controllers/api/v1/Auth.controller.js index 0d6dc9d..1b5e46b 100644 --- a/app/controllers/api/v1/Auth.controller.js +++ b/app/controllers/api/v1/Auth.controller.js @@ -71,7 +71,7 @@ class AuthController extends Controller { const user = new User({ first_name: req.body.first_name, last_name: req.body.last_name, - uid: req.body.uid, + uid: req.body.uid.toLowerCase(), email: req.body.email, trap: 'password_reset', // Force user to reset password }) @@ -297,7 +297,7 @@ class AuthController extends Controller { .api() const user = new User({ - uid: req.body.uid, + uid: req.body.uid.toLowerCase(), email: req.body.email, first_name: req.body.first_name, last_name: req.body.last_name, @@ -417,7 +417,7 @@ class AuthController extends Controller { user.first_name = req.body.first_name user.last_name = req.body.last_name - user.uid = req.body.uid + user.uid = req.body.uid.toLowerCase() user.email = req.body.email if ( req.body.tagline ) @@ -493,7 +493,7 @@ class AuthController extends Controller { if ( is_valid ) { const User = this.models.get('auth:User') - const user = await User.findOne({uid: req.body.username}) + const user = await User.findOne({uid: req.body.username.toLowerCase()}) if ( !user || !user.can_login ) is_valid = false } @@ -511,7 +511,7 @@ class AuthController extends Controller { const data = {} if ( req.body.username ) { const existing_user = await User.findOne({ - uid: req.body.username, + uid: req.body.username.toLowerCase(), }) data.username_taken = !!existing_user @@ -544,7 +544,8 @@ class AuthController extends Controller { .message(req.T('auth.unable_to_complete')) .api({ errors }) - const login_args = await flitter.get_login_args(req.body) + const [username, ...other_args] = await flitter.get_login_args(req.body) + const login_args = [username.toLowerCase(), ...other_args] const user = await flitter.login.apply(flitter, login_args) if ( !user ) diff --git a/app/controllers/api/v1/LDAP.controller.js b/app/controllers/api/v1/LDAP.controller.js index ad8eeb2..6de2103 100644 --- a/app/controllers/api/v1/LDAP.controller.js +++ b/app/controllers/api/v1/LDAP.controller.js @@ -96,7 +96,7 @@ class LDAPController extends Controller { // Make sure the uid is free const User = this.models.get('auth:User') - const existing_user = await User.findOne({ uid: req.body.uid }) + const existing_user = await User.findOne({ uid: req.body.uid.toLowerCase() }) if ( existing_user ) return res.status(400) .message(req.T('api.user_already_exists')) @@ -113,7 +113,7 @@ class LDAPController extends Controller { // Create the client const Client = this.models.get('ldap:Client') const client = await Client.create({ - uid: req.body.uid, + uid: req.body.uid.toLowerCase(), password: req.body.password, name: req.body.name, }) @@ -210,16 +210,16 @@ class LDAPController extends Controller { } // Update the uid - if ( req.body.uid !== user.uid ) { + if ( req.body.uid.toLowerCase() !== user.uid ) { // Make sure the UID is free const User = this.models.get('auth:User') - const existing_user = await User.findOne({ uid: req.body.uid }) + const existing_user = await User.findOne({ uid: req.body.uid.toLowerCase() }) if ( existing_user ) return res.status(400) .message(req.T('api.user_already_exists')) .api() - user.uid = req.body.uid + user.uid = req.body.uid.toLowerCase() } // Update the password diff --git a/app/controllers/saml/SAML.controller.js b/app/controllers/saml/SAML.controller.js index 0e8145c..eb0c5b7 100644 --- a/app/controllers/saml/SAML.controller.js +++ b/app/controllers/saml/SAML.controller.js @@ -67,7 +67,7 @@ class SAMLController extends Controller { key: await this.saml.private_key(), protocolBinding: 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect', clearIdPSession: done => { - this.output.info(`${req.T('saml.clear_idp_session')} ${req.user.uid}`) + this.output.info(`${req.T('saml.clear_idp_session')} ${req.user.uid.toLowerCase()}`) req.saml.participants.clear().then(async () => { if ( this.saml.config().slo.end_coreid_session ) { await req.user.logout(req) diff --git a/app/ldap/controllers/Users.controller.js b/app/ldap/controllers/Users.controller.js index 631d2fe..d9347b8 100644 --- a/app/ldap/controllers/Users.controller.js +++ b/app/ldap/controllers/Users.controller.js @@ -52,7 +52,7 @@ class UsersController extends LDAPController { first_name: req_data.cn ? req_data.cn[0] : '', last_name: req_data.sn ? req_data.sn[0] : '', email: req_data.mail ? req_data.mail[0] : '', - username: req_data.uid ? req_data.uid[0] : '', + username: req_data.uid ? req_data.uid[0].toLowerCase() : '', password: req_data.userpassword ? req_data.userpassword[0] : '', } @@ -327,7 +327,7 @@ class UsersController extends LDAPController { try { if ( typeof dn === 'string' ) dn = LDAP.parseDN(dn) - return dn.rdns[0].attrs[uid_field].value + return dn.rdns[0].attrs[uid_field].value.toLowerCase() } catch (e) {} } @@ -335,7 +335,7 @@ class UsersController extends LDAPController { const uid = this.get_uid_from_dn(dn) if ( uid ) { const User = this.models.get('auth:User') - return User.findOne({uid, ldap_visible: true}) + return User.findOne({uid: uid.toLowerCase(), ldap_visible: true}) } } } diff --git a/app/models/auth/User.model.js b/app/models/auth/User.model.js index 4f9a43d..221bab3 100644 --- a/app/models/auth/User.model.js +++ b/app/models/auth/User.model.js @@ -173,7 +173,7 @@ class User extends AuthUser { const Policy = this.models.get('iam:Policy') const ldap_data = { - uid: this.uid, + uid: this.uid.toLowerCase(), uuid: this.uuid, cn: this.first_name, sn: this.last_name, @@ -213,7 +213,7 @@ class User extends AuthUser { } get dn() { - return LDAP.parseDN(`uid=${this.uid},${this.ldap_server.auth_dn().format(this.configs.get('ldap:server.format'))}`) + return LDAP.parseDN(`uid=${this.uid.toLowerCase()},${this.ldap_server.auth_dn().format(this.configs.get('ldap:server.format'))}`) } // The following are used by OpenID connect @@ -227,15 +227,15 @@ class User extends AuthUser { given_name: this.first_name, locale: 'en_US', // TODO name: `${this.first_name} ${this.last_name}`, - preferred_username: this.uid, - username: this.uid, + preferred_username: this.uid.toLowerCase(), + username: this.uid.toLowerCase(), } } static async findByLogin(login) { return this.findOne({ active: true, - uid: login, + uid: login.toLowerCase(), }) } diff --git a/app/models/iam/Policy.model.js b/app/models/iam/Policy.model.js index b3064be..dddf70f 100644 --- a/app/models/iam/Policy.model.js +++ b/app/models/iam/Policy.model.js @@ -118,7 +118,7 @@ class PolicyModel extends Model { if ( this.entity_type === 'user' ) { const User = this.models.get('auth:User') const user = await User.findById(this.entity_id) - entity_display = `User: ${user.last_name}, ${user.first_name} (${user.uid})` + entity_display = `User: ${user.last_name}, ${user.first_name} (${user.uid.toLowerCase()})` } else if ( this.entity_type === 'group' ) { const Group = this.models.get('auth:Group') const group = await Group.findById(this.entity_id) diff --git a/app/models/ldap/Client.model.js b/app/models/ldap/Client.model.js index 5e64a95..2a6d75a 100644 --- a/app/models/ldap/Client.model.js +++ b/app/models/ldap/Client.model.js @@ -19,7 +19,7 @@ class ClientModel extends Model { const user = new User({ first_name: name, last_name: '(LDAP Agent)', - uid, + uid: uid.toLowerCase(), roles: ['ldap_client'], }) @@ -58,7 +58,7 @@ class ClientModel extends Model { id: this.id, name: this.name, user_id: user.id, - uid: user.uid, + uid: user.uid.toLowerCase(), last_invocation: this.last_invocation, permissions: [...user.permissions, ...role_permissions], } diff --git a/app/routing/middleware/SAMLUtility.middleware.js b/app/routing/middleware/SAMLUtility.middleware.js index 2bc95d6..fee67e6 100644 --- a/app/routing/middleware/SAMLUtility.middleware.js +++ b/app/routing/middleware/SAMLUtility.middleware.js @@ -17,7 +17,7 @@ class SessionParticipantStore extends Injectable { async issue({ service_provider }) { const sp = new this.SessionParticipant({ service_provider_id: service_provider.id, - name_id: this.request.user.uid, + name_id: this.request.user.uid.toLowerCase(), // session_index: this.get_index(), slo_url: service_provider.slo_url, // TODO sp_cert, diff --git a/app/services/MFA.service.js b/app/services/MFA.service.js index 75f49c9..6022d56 100644 --- a/app/services/MFA.service.js +++ b/app/services/MFA.service.js @@ -10,7 +10,7 @@ class MFAService extends Service { secret(user) { return speakeasy.generateSecret({ length: this.configs.get('auth.mfa.secret_length') ?? 20, - name: `${this.configs.get('app.name')} (${user.uid})`, + name: `${this.configs.get('app.name')} (${user.uid.toLowerCase()})`, }) } diff --git a/app/services/Vue.service.js b/app/services/Vue.service.js index 6b420e5..efaf5f6 100644 --- a/app/services/Vue.service.js +++ b/app/services/Vue.service.js @@ -25,7 +25,7 @@ class VueService extends Service { user: { first_name: req.user.first_name, last_name: req.user.last_name, - username: req.user.uid, + username: req.user.uid.toLowerCase(), email: req.user.email, tagline: req.user.tagline, user_id: req.user.id, diff --git a/app/unit/OpenIDConnectUnit.js b/app/unit/OpenIDConnectUnit.js index e885637..d7f120f 100644 --- a/app/unit/OpenIDConnectUnit.js +++ b/app/unit/OpenIDConnectUnit.js @@ -28,7 +28,7 @@ class OpenIDConnectUnit extends Unit { clients: [], interactions: { interactions, - url: (ctx, interaction) => `/openid/interaction/${ctx.oidc.uid}`, + url: (ctx, interaction) => `/openid/interaction/${ctx.oidc.uid.toLowerCase()}`, }, cookies: { long: { signed: true, maxAge: 24 * 60 * 60 * 1000 }, // 1 day, ms