twentyhq / twenty

Building a modern alternative to Salesforce, powered by the community.
https://twenty.com
Other
23.03k stars 2.41k forks source link

Using LDAP for authentication #8660

Open code1704 opened 15 hours ago

code1704 commented 15 hours ago

Any plan to support LDAP Auth (like https://www.metabase.com/learn/metabase-basics/administration/permissions/ldap-auth-access-control)?

BOHEUS commented 15 hours ago

I'd say it should be possible some time in the future but don't know exactly when, my rough estimate is at least Q2 2025

CC: @Bonapara

code1704 commented 9 hours ago

Below is what Github copilot tells how to support LDAP. Will that work?

Based on the search results, there are no direct mentions of LDAP integration or support in the twentyhq/twenty repository. However, there are multiple references to Single Sign-On (SSO) and various authentication methods.

Here are some relevant findings:

For LDAP integration, you might need to extend the current authentication services to support LDAP. This typically involves:

  1. LDAP Configuration: Adding LDAP-specific settings in your environment configuration.
  2. LDAP Authentication Logic: Implementing LDAP authentication in your service layer, similar to existing SSO methods.

You can start by examining the existing SSO implementations and then add LDAP-specific logic and configuration.

To add LDAP (Active Directory) authentication support for the Twenty CRM repository, you would need to create or modify several files to integrate with LDAP. Below are the steps and example code snippets for integrating LDAP authentication:

  1. Install LDAP Dependencies: Ensure you have installed the necessary LDAP libraries. For Node.js, you can use ldapjs.

    npm install ldapjs
  2. Add LDAP Configuration: Add LDAP configuration settings to your environment configuration file.

    # LDAP Configuration
    LDAP_URL=ldap://your-ldap-server.com
    LDAP_BIND_DN=cn=read-only-admin,dc=example,dc=com
    LDAP_BIND_PASSWORD=your-password
    LDAP_SEARCH_BASE=dc=example,dc=com
    LDAP_SEARCH_FILTER=(uid={{username}})
  3. Create LDAP Authentication Service: Create a new service to handle LDAP authentication.

    // packages/twenty-server/src/engine/core-modules/auth/services/ldap-auth.service.ts
    
    import ldap from 'ldapjs';
    
    export class LdapAuthService {
     private client: ldap.Client;
    
     constructor() {
       this.client = ldap.createClient({
         url: process.env.LDAP_URL,
       });
     }
    
     private bindAdmin() {
       return new Promise((resolve, reject) => {
         this.client.bind(process.env.LDAP_BIND_DN, process.env.LDAP_BIND_PASSWORD, (err) => {
           if (err) return reject(err);
           resolve(true);
         });
       });
     }
    
     private searchUser(username: string) {
       const opts = {
         filter: process.env.LDAP_SEARCH_FILTER.replace('{{username}}', username),
         scope: 'sub',
       };
    
       return new Promise((resolve, reject) => {
         this.client.search(process.env.LDAP_SEARCH_BASE, opts, (err, res) => {
           if (err) return reject(err);
    
           let user = null;
           res.on('searchEntry', (entry) => {
             user = entry.object;
           });
    
           res.on('end', () => {
             resolve(user);
           });
    
           res.on('error', (err) => {
             reject(err);
           });
         });
       });
     }
    
     private authenticateUser(dn: string, password: string) {
       return new Promise((resolve, reject) => {
         this.client.bind(dn, password, (err) => {
           if (err) return reject(err);
           resolve(true);
         });
       });
     }
    
     public async authenticate(username: string, password: string) {
       await this.bindAdmin();
       const user: any = await this.searchUser(username);
       if (!user) throw new Error('User not found');
    
       await this.authenticateUser(user.dn, password);
       return user;
     }
    }
  4. Integrate LDAP Authentication in Sign-In Service: Modify the sign-in service to include LDAP authentication.

    // packages/twenty-server/src/engine/core-modules/auth/services/sign-in-up.service.ts
    
    import { LdapAuthService } from './ldap-auth.service';
    
    export class SignInUpService {
     private ldapAuthService: LdapAuthService;
    
     constructor() {
       this.ldapAuthService = new LdapAuthService();
     }
    
     // Existing methods...
    
     public async signInWithLdap(email: string, password: string) {
       try {
         const user = await this.ldapAuthService.authenticate(email, password);
         // Handle the user object as needed, e.g., create a session, generate JWT, etc.
         return user;
       } catch (error) {
         throw new AuthException('LDAP Authentication failed', AuthExceptionCode.INVALID_INPUT);
       }
     }
    }
  5. Update Routes and Controllers: Update your routes and controllers to handle LDAP sign-in requests.

    // packages/twenty-server/src/engine/core-modules/auth/controllers/auth.controller.ts
    
    import { SignInUpService } from '../services/sign-in-up.service';
    
    export class AuthController {
     private signInUpService: SignInUpService;
    
     constructor() {
       this.signInUpService = new SignInUpService();
     }
    
     public async signInLdap(req, res) {
       const { email, password } = req.body;
       try {
         const user = await this.signInUpService.signInWithLdap(email, password);
         res.status(200).json(user);
       } catch (error) {
         res.status(401).json({ message: 'LDAP Authentication failed' });
       }
     }
    }

    And update your routes:

    // packages/twenty-server/src/engine/core-modules/auth/routes/auth.routes.ts
    
    import express from 'express';
    import { AuthController } from '../controllers/auth.controller';
    
    const router = express.Router();
    const authController = new AuthController();
    
    router.post('/ldap-signin', authController.signInLdap.bind(authController));
    
    export default router;
  6. Test the Integration: Ensure you test the LDAP authentication thoroughly to handle various edge cases and errors.

This guide provides a basic structure for integrating LDAP authentication into the Twenty CRM application. You may need to adjust the code to fit the existing architecture and handle specific requirements.

Bonapara commented 2 hours ago

Hi @code1704, we are about to add SAML and OIDC, with an estimated time of arrival in one month. Would that work for you? What additional benefits would LDAP provide?