From a4a62f23b6595166fb660134a258f6569d7f512e Mon Sep 17 00:00:00 2001 From: Laurin Wolf Date: Tue, 26 Apr 2022 09:50:02 +0200 Subject: [PATCH 1/4] =?UTF-8?q?feat(auth):=20=F0=9F=94=92=20add=20gitlab?= =?UTF-8?q?=20provider?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/builder/assets/logos/GitlabLogo.tsx | 13 +++++++++++++ apps/builder/assets/logos/index.tsx | 1 + .../components/auth/SocialLoginButtons.tsx | 18 +++++++++++++++++- apps/builder/pages/api/auth/[...nextauth].ts | 15 +++++++++++++++ 4 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 apps/builder/assets/logos/GitlabLogo.tsx diff --git a/apps/builder/assets/logos/GitlabLogo.tsx b/apps/builder/assets/logos/GitlabLogo.tsx new file mode 100644 index 000000000..97d0253c6 --- /dev/null +++ b/apps/builder/assets/logos/GitlabLogo.tsx @@ -0,0 +1,13 @@ +import { IconProps, Icon } from '@chakra-ui/react' + +export const GitlabLogo = (props: IconProps) => ( + + + + + + + + + +) diff --git a/apps/builder/assets/logos/index.tsx b/apps/builder/assets/logos/index.tsx index e582658dd..454eacdcb 100644 --- a/apps/builder/assets/logos/index.tsx +++ b/apps/builder/assets/logos/index.tsx @@ -1,4 +1,5 @@ export * from './GiphyLogo' +export * from './GitlabLogo' export * from './GoogleAnalyticsLogo' export * from './GoogleSheetsLogo' export * from './GtmLogo' diff --git a/apps/builder/components/auth/SocialLoginButtons.tsx b/apps/builder/components/auth/SocialLoginButtons.tsx index 51f167cc9..0c9805cbf 100644 --- a/apps/builder/components/auth/SocialLoginButtons.tsx +++ b/apps/builder/components/auth/SocialLoginButtons.tsx @@ -4,7 +4,7 @@ import { signIn, useSession } from 'next-auth/react' import { useRouter } from 'next/router' import React from 'react' import { stringify } from 'qs' -import { FacebookLogo, GoogleLogo } from 'assets/logos' +import { FacebookLogo, GoogleLogo, GitlabLogo } from 'assets/logos' export const SocialLoginButtons = () => { const { query } = useRouter() @@ -25,6 +25,11 @@ export const SocialLoginButtons = () => { callbackUrl: `/typebots?${stringify(query)}`, }) + const handleGitlabClick = async () => + signIn('gitlab', { + callbackUrl: `/typebots?${stringify(query)}`, + }) + return ( {process.env.NEXT_PUBLIC_GITHUB_CLIENT_ID && ( @@ -60,6 +65,17 @@ export const SocialLoginButtons = () => { Continue with Facebook )} + {process.env.NEXT_PUBLIC_GITLAB_CLIENT_ID && ( + + )} ) } diff --git a/apps/builder/pages/api/auth/[...nextauth].ts b/apps/builder/pages/api/auth/[...nextauth].ts index a7f0583d0..c15527c1a 100644 --- a/apps/builder/pages/api/auth/[...nextauth].ts +++ b/apps/builder/pages/api/auth/[...nextauth].ts @@ -1,6 +1,7 @@ import NextAuth from 'next-auth' import EmailProvider from 'next-auth/providers/email' import GitHubProvider from 'next-auth/providers/github' +import GitlabProvider from 'next-auth/providers/gitlab' import GoogleProvider from 'next-auth/providers/google' import FacebookProvider from 'next-auth/providers/facebook' import prisma from 'libs/prisma' @@ -60,6 +61,20 @@ if ( }) ) +if ( + process.env.NEXT_PUBLIC_GITLAB_CLIENT_ID && + process.env.GITLAB_CLIENT_SECRET +) { + const BASE_URL = process.env.NEXT_PUBLIC_GITLAB_BASE_URL || 'gitlab.com' + providers.push(GitlabProvider({ + clientId: process.env.NEXT_PUBLIC_GITLAB_CLIENT_ID, + clientSecret: process.env.GITLAB_CLIENT_SECRET, + authorization: `${BASE_URL}/oauth/authorize?scope=read_api`, + token: `${BASE_URL}/oauth/token`, + userinfo: `${BASE_URL}/api/v4/user`, + })) +} + const handler = (req: NextApiRequest, res: NextApiResponse) => { if (req.method === 'HEAD') { res.status(200) From b2b0685298d5417475b21885d5b198a3a9a306bb Mon Sep 17 00:00:00 2001 From: Laurin Wolf Date: Tue, 26 Apr 2022 09:50:14 +0200 Subject: [PATCH 2/4] =?UTF-8?q?docs(auth):=20=F0=9F=93=9D=20add=20gitlab?= =?UTF-8?q?=20idp=20env=20variables?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/docs/docs/self-hosting/configuration.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/apps/docs/docs/self-hosting/configuration.md b/apps/docs/docs/self-hosting/configuration.md index 12433e661..30d77481b 100644 --- a/apps/docs/docs/self-hosting/configuration.md +++ b/apps/docs/docs/self-hosting/configuration.md @@ -80,6 +80,23 @@ You can create your own GitHub OAuth app [here](https://github.com/settings/deve

+

GitLab (Auth)

+

+ +Used for authenticating with GitLab. +Follow the official GitLab guide for creating OAuth2 applications [here](https://docs.gitlab.com/ee/integration/oauth_provider.html). +The Authorization callback URL should be `$NEXTAUTH_URL/api/auth/callback/gitlab` + +| Parameter | Default | Description | +| ---------------------------- | ------- | -------------------------------------------------------------------------------------| +| NEXT_PUBLIC_GITLAB_CLIENT_ID | -- | Application client ID. Also used to check if it is enabled in the front-end | +| GITLAB_CLIENT_SECRET | -- | Application secret | +| NEXT_PUBLIC_GITLAB_BASE_URL | -- | Base URL of the GitLab instance, e.g. `https://gitlab.com` | +| NEXT_PUBLIC_GITLAB_NAME | -- | Name of the GitLab instance, used for the SSO Login Button, e.g. `GitLab` | +| GITLAB_REQUIRED_GROUPS | -- | Comma-separated list of groups the user has to be a direct member of, e.g. `foo,bar` | + +

+

Facebook (Auth)

From 3db753e886955f7f534d0d0af7f18beb96c845c9 Mon Sep 17 00:00:00 2001 From: Laurin Wolf Date: Tue, 26 Apr 2022 09:51:11 +0200 Subject: [PATCH 3/4] =?UTF-8?q?feat(auth):=20=F0=9F=94=92=20add=20checking?= =?UTF-8?q?=20for=20required=20group?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/builder/pages/api/auth/[...nextauth].ts | 35 +++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/apps/builder/pages/api/auth/[...nextauth].ts b/apps/builder/pages/api/auth/[...nextauth].ts index c15527c1a..92841037e 100644 --- a/apps/builder/pages/api/auth/[...nextauth].ts +++ b/apps/builder/pages/api/auth/[...nextauth].ts @@ -1,4 +1,4 @@ -import NextAuth from 'next-auth' +import NextAuth, { Account } from 'next-auth' import EmailProvider from 'next-auth/providers/email' import GitHubProvider from 'next-auth/providers/github' import GitlabProvider from 'next-auth/providers/gitlab' @@ -96,6 +96,14 @@ const handler = (req: NextApiRequest, res: NextApiResponse) => { user: userFromDb, } }, + signIn: async ({ account }) => { + const requiredGroups = getRequiredGroups(account.provider) + if (requiredGroups.length > 0) { + const userGroups = await getUserGroups(account) + return checkHasGroups(userGroups, requiredGroups) + } + return true + }, }, }) } @@ -113,4 +121,29 @@ const updateLastActivityDate = async (user: User) => { }) } +async function getUserGroups(account: Account): Promise { + switch (account.provider) { + case 'gitlab': { + const res = await fetch( + `${process.env.NEXT_PUBLIC_GITLAB_BASE_URL || 'gitlab.com'}/api/v4/groups`, + { headers: { 'Authorization': `Bearer ${account.access_token}` } }, + ) + const userGroups: string[] = (await res.json()) + return userGroups.map((group: any) => group.full_path) + } + default: return [] + } +} + +function getRequiredGroups(provider: string): string[] { + switch (provider) { + case 'gitlab': return process.env.GITLAB_REQUIRED_GROUPS?.split(',') || [] + default: return [] + } +} + +function checkHasGroups(userGroups: string[], requiredGroups: string[]) { + return userGroups?.some(userGroup => requiredGroups?.includes(userGroup)) +} + export default withSentry(handler) From fe26e8990286e6cea1ad5d4bb2af4a323e3523a0 Mon Sep 17 00:00:00 2001 From: Baptiste Arnaud Date: Sat, 30 Apr 2022 07:10:02 -0700 Subject: [PATCH 4/4] =?UTF-8?q?fix:=20=F0=9F=8E=A8=20Formatting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/builder/pages/api/auth/[...nextauth].ts | 44 +++++++++++--------- apps/docs/docs/self-hosting/configuration.md | 14 +++---- 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/apps/builder/pages/api/auth/[...nextauth].ts b/apps/builder/pages/api/auth/[...nextauth].ts index 92841037e..81e6608ce 100644 --- a/apps/builder/pages/api/auth/[...nextauth].ts +++ b/apps/builder/pages/api/auth/[...nextauth].ts @@ -65,14 +65,16 @@ if ( process.env.NEXT_PUBLIC_GITLAB_CLIENT_ID && process.env.GITLAB_CLIENT_SECRET ) { - const BASE_URL = process.env.NEXT_PUBLIC_GITLAB_BASE_URL || 'gitlab.com' - providers.push(GitlabProvider({ - clientId: process.env.NEXT_PUBLIC_GITLAB_CLIENT_ID, - clientSecret: process.env.GITLAB_CLIENT_SECRET, - authorization: `${BASE_URL}/oauth/authorize?scope=read_api`, - token: `${BASE_URL}/oauth/token`, - userinfo: `${BASE_URL}/api/v4/user`, - })) + const BASE_URL = process.env.GITLAB_BASE_URL || 'https://gitlab.com' + providers.push( + GitlabProvider({ + clientId: process.env.NEXT_PUBLIC_GITLAB_CLIENT_ID, + clientSecret: process.env.GITLAB_CLIENT_SECRET, + authorization: `${BASE_URL}/oauth/authorize?scope=read_api`, + token: `${BASE_URL}/oauth/token`, + userinfo: `${BASE_URL}/api/v4/user`, + }) + ) } const handler = (req: NextApiRequest, res: NextApiResponse) => { @@ -121,29 +123,31 @@ const updateLastActivityDate = async (user: User) => { }) } -async function getUserGroups(account: Account): Promise { +const getUserGroups = async (account: Account): Promise => { switch (account.provider) { case 'gitlab': { const res = await fetch( - `${process.env.NEXT_PUBLIC_GITLAB_BASE_URL || 'gitlab.com'}/api/v4/groups`, - { headers: { 'Authorization': `Bearer ${account.access_token}` } }, + `${process.env.GITLAB_BASE_URL || 'https://gitlab.com'}/api/v4/groups`, + { headers: { Authorization: `Bearer ${account.access_token}` } } ) - const userGroups: string[] = (await res.json()) - return userGroups.map((group: any) => group.full_path) + const userGroups = await res.json() + return userGroups.map((group: { full_path: string }) => group.full_path) } - default: return [] + default: + return [] } } -function getRequiredGroups(provider: string): string[] { +const getRequiredGroups = (provider: string): string[] => { switch (provider) { - case 'gitlab': return process.env.GITLAB_REQUIRED_GROUPS?.split(',') || [] - default: return [] + case 'gitlab': + return process.env.GITLAB_REQUIRED_GROUPS?.split(',') || [] + default: + return [] } } -function checkHasGroups(userGroups: string[], requiredGroups: string[]) { - return userGroups?.some(userGroup => requiredGroups?.includes(userGroup)) -} +const checkHasGroups = (userGroups: string[], requiredGroups: string[]) => + userGroups?.some((userGroup) => requiredGroups?.includes(userGroup)) export default withSentry(handler) diff --git a/apps/docs/docs/self-hosting/configuration.md b/apps/docs/docs/self-hosting/configuration.md index 30d77481b..732745768 100644 --- a/apps/docs/docs/self-hosting/configuration.md +++ b/apps/docs/docs/self-hosting/configuration.md @@ -87,13 +87,13 @@ Used for authenticating with GitLab. Follow the official GitLab guide for creating OAuth2 applications [here](https://docs.gitlab.com/ee/integration/oauth_provider.html). The Authorization callback URL should be `$NEXTAUTH_URL/api/auth/callback/gitlab` -| Parameter | Default | Description | -| ---------------------------- | ------- | -------------------------------------------------------------------------------------| -| NEXT_PUBLIC_GITLAB_CLIENT_ID | -- | Application client ID. Also used to check if it is enabled in the front-end | -| GITLAB_CLIENT_SECRET | -- | Application secret | -| NEXT_PUBLIC_GITLAB_BASE_URL | -- | Base URL of the GitLab instance, e.g. `https://gitlab.com` | -| NEXT_PUBLIC_GITLAB_NAME | -- | Name of the GitLab instance, used for the SSO Login Button, e.g. `GitLab` | -| GITLAB_REQUIRED_GROUPS | -- | Comma-separated list of groups the user has to be a direct member of, e.g. `foo,bar` | +| Parameter | Default | Description | +| ---------------------------- | ------------------ | ------------------------------------------------------------------------------------ | --- | +| NEXT_PUBLIC_GITLAB_CLIENT_ID | -- | Application client ID. Also used to check if it is enabled in the front-end | +| GITLAB_CLIENT_SECRET | -- | Application secret | +| GITLAB_BASE_URL | https://gitlab.com | Base URL of the GitLab instance | | +| GITLAB_REQUIRED_GROUPS | -- | Comma-separated list of groups the user has to be a direct member of, e.g. `foo,bar` | +| NEXT_PUBLIC_GITLAB_NAME | GitLab | Name of the GitLab instance, used for the SSO Login Button |