summaryrefslogtreecommitdiffstats
path: root/packages/wekan-ldap/server/loginHandler.js
diff options
context:
space:
mode:
Diffstat (limited to 'packages/wekan-ldap/server/loginHandler.js')
-rw-r--r--packages/wekan-ldap/server/loginHandler.js224
1 files changed, 224 insertions, 0 deletions
diff --git a/packages/wekan-ldap/server/loginHandler.js b/packages/wekan-ldap/server/loginHandler.js
new file mode 100644
index 00000000..a8f013d7
--- /dev/null
+++ b/packages/wekan-ldap/server/loginHandler.js
@@ -0,0 +1,224 @@
+import {slug, getLdapUsername, getLdapEmail, getLdapUserUniqueID, syncUserData, addLdapUser} from './sync';
+import LDAP from './ldap';
+import { log_debug, log_info, log_warn, log_error } from './logger';
+
+function fallbackDefaultAccountSystem(bind, username, password) {
+ if (typeof username === 'string') {
+ if (username.indexOf('@') === -1) {
+ username = {username};
+ } else {
+ username = {email: username};
+ }
+ }
+
+ log_info('Fallback to default account system: ', username );
+
+ const loginRequest = {
+ user: username,
+ password: {
+ digest: SHA256(password),
+ algorithm: 'sha-256',
+ },
+ };
+ log_debug('Fallback options: ', loginRequest);
+
+ return Accounts._runLoginHandlers(bind, loginRequest);
+}
+
+Accounts.registerLoginHandler('ldap', function(loginRequest) {
+ if (!loginRequest.ldap || !loginRequest.ldapOptions) {
+ return undefined;
+ }
+
+ log_info('Init LDAP login', loginRequest.username);
+
+ if (LDAP.settings_get('LDAP_ENABLE') !== true) {
+ return fallbackDefaultAccountSystem(this, loginRequest.username, loginRequest.ldapPass);
+ }
+
+ const self = this;
+ const ldap = new LDAP();
+ let ldapUser;
+
+ try {
+ ldap.connectSync();
+ const users = ldap.searchUsersSync(loginRequest.username);
+
+ if (users.length !== 1) {
+ log_info('Search returned', users.length, 'record(s) for', loginRequest.username);
+ throw new Error('User not Found');
+ }
+
+ if (ldap.authSync(users[0].dn, loginRequest.ldapPass) === true) {
+ if (ldap.isUserInGroup(loginRequest.username, users[0])) {
+ ldapUser = users[0];
+ } else {
+ throw new Error('User not in a valid group');
+ }
+ } else {
+ log_info('Wrong password for', loginRequest.username);
+ }
+ } catch (error) {
+ log_error(error);
+ }
+
+ if (ldapUser === undefined) {
+ if (LDAP.settings_get('LDAP_LOGIN_FALLBACK') === true) {
+ return fallbackDefaultAccountSystem(self, loginRequest.username, loginRequest.ldapPass);
+ }
+
+ throw new Meteor.Error('LDAP-login-error', `LDAP Authentication failed with provided username [${ loginRequest.username }]`);
+ }
+
+ // Look to see if user already exists
+
+ let userQuery;
+
+ const Unique_Identifier_Field = getLdapUserUniqueID(ldapUser);
+ let user;
+
+ // Attempt to find user by unique identifier
+
+ if (Unique_Identifier_Field) {
+ userQuery = {
+ 'services.ldap.id': Unique_Identifier_Field.value,
+ };
+
+ log_info('Querying user');
+ log_debug('userQuery', userQuery);
+
+ user = Meteor.users.findOne(userQuery);
+ }
+
+ // Attempt to find user by username
+
+ let username;
+ let email;
+
+ if (LDAP.settings_get('LDAP_USERNAME_FIELD') !== '') {
+ username = slug(getLdapUsername(ldapUser));
+ } else {
+ username = slug(loginRequest.username);
+ }
+
+ if(LDAP.settings_get('LDAP_EMAIL_FIELD') !== '') {
+ email = getLdapEmail(ldapUser);
+ }
+
+ if (!user) {
+ if(email && LDAP.settings_get('LDAP_EMAIL_MATCH_REQUIRE') === true) {
+ if(LDAP.settings_get('LDAP_EMAIL_MATCH_VERIFIED') === true) {
+ userQuery = {
+ '_id' : username,
+ 'emails.0.address' : email,
+ 'emails.0.verified' : true
+ };
+ } else {
+ userQuery = {
+ '_id' : username,
+ 'emails.0.address' : email
+ };
+ }
+ } else {
+ userQuery = {
+ username
+ };
+ }
+
+ log_debug('userQuery', userQuery);
+
+ user = Meteor.users.findOne(userQuery);
+ }
+
+ // Attempt to find user by e-mail address only
+
+ if (!user && email && LDAP.settings_get('LDAP_EMAIL_MATCH_ENABLE') === true) {
+
+ log_info('No user exists with username', username, '- attempting to find by e-mail address instead');
+
+ if(LDAP.settings_get('LDAP_EMAIL_MATCH_VERIFIED') === true) {
+ userQuery = {
+ 'emails.0.address': email,
+ 'emails.0.verified' : true
+ };
+ } else {
+ userQuery = {
+ 'emails.0.address' : email
+ };
+ }
+
+ log_debug('userQuery', userQuery);
+
+ user = Meteor.users.findOne(userQuery);
+
+ }
+
+ // Login user if they exist
+ if (user) {
+ if (user.authenticationMethod !== 'ldap' && LDAP.settings_get('LDAP_MERGE_EXISTING_USERS') !== true) {
+ log_info('User exists without "authenticationMethod : ldap"');
+ throw new Meteor.Error('LDAP-login-error', `LDAP Authentication succeded, but there's already a matching Wekan account in MongoDB`);
+ }
+
+ log_info('Logging user');
+
+ const stampedToken = Accounts._generateStampedLoginToken();
+ const update_data = {
+ $push: {
+ 'services.resume.loginTokens': Accounts._hashStampedToken(stampedToken),
+ },
+ };
+
+ if( LDAP.settings_get('LDAP_SYNC_GROUP_ROLES') === true ) {
+ log_debug('Updating Groups/Roles');
+ const groups = ldap.getUserGroups(username, ldapUser);
+
+ if( groups.length > 0 ) {
+ Roles.setUserRoles(user._id, groups );
+ log_info(`Updated roles to:${ groups.join(',')}`);
+ }
+ }
+
+ Meteor.users.update(user._id, update_data );
+
+ syncUserData(user, ldapUser);
+
+ if (LDAP.settings_get('LDAP_LOGIN_FALLBACK') === true) {
+ Accounts.setPassword(user._id, loginRequest.ldapPass, {logout: false});
+ }
+
+ return {
+ userId: user._id,
+ token: stampedToken.token,
+ };
+ }
+
+ // Create new user
+
+ log_info('User does not exist, creating', username);
+
+ if (LDAP.settings_get('LDAP_USERNAME_FIELD') === '') {
+ username = undefined;
+ }
+
+ if (LDAP.settings_get('LDAP_LOGIN_FALLBACK') !== true) {
+ loginRequest.ldapPass = undefined;
+ }
+
+ const result = addLdapUser(ldapUser, username, loginRequest.ldapPass);
+
+ if( LDAP.settings_get('LDAP_SYNC_GROUP_ROLES') === true ) {
+ const groups = ldap.getUserGroups(username, ldapUser);
+ if( groups.length > 0 ) {
+ Roles.setUserRoles(result.userId, groups );
+ log_info(`Set roles to:${ groups.join(',')}`);
+ }
+ }
+
+
+ if (result instanceof Error) {
+ throw result;
+ }
+
+ return result;
+});