SAML variables explainers and refactoring

feature/saml-login
Omar López 2022-01-12 19:49:18 -07:00
parent ac359c61f2
commit 040e4d214a
7 changed files with 40 additions and 32 deletions

View File

@ -1,4 +1,4 @@
# Set this value to 'agree' to accept our license:
# Set this value to 'agree' to accept our license:
# LICENSE: https://github.com/calendso/calendso/blob/main/LICENSE
#
# Summary of terms:
@ -10,7 +10,15 @@ NEXT_PUBLIC_LICENSE_CONSENT=''
# DATABASE_URL='postgresql://<user>:<pass>@<db-host>:<db-port>/<db-name>'
DATABASE_URL="postgresql://postgres:@localhost:5450/calendso"
GOOGLE_API_CREDENTIALS='secret'
# Needed to enable Google Calendar integrationa and Login with Google
# @see https://github.com/calendso/calendso#obtaining-the-google-api-credentials
GOOGLE_API_CREDENTIALS='{}'
# To enable Login with Google you need to:
# 1. Set `GOOGLE_API_CREDENTIALS`
# 2. Set `GOOGLE_ENABLE_LOGIN` to `true`
# 3. Setup `SAML_DATABASE_URL` and `SAML_ADMINS` down below.
GOOGLE_ENABLE_LOGIN=false
BASE_URL='http://localhost:3000'
NEXT_PUBLIC_APP_URL='http://localhost:3000'
@ -19,13 +27,10 @@ JWT_SECRET='secret'
# This is used so we can bypass emails in auth flows for E2E testing
PLAYWRIGHT_SECRET=
# Google OAuth client id and secret to enable login with Google
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
# Enable SAML login using https://github.com/boxyhq/jackson
# To enable SAML login, set both these variables
# SAML_DATABASE_URL="postgresql://postgres:@localhost:5450/cal-saml"
# SAML_ADMINS='pro@example.com'
# If you want to Login with Google as well, you need to setup `GOOGLE_API_CREDENTIALS` and `GOOGLE_LOGIN_ENABLE` above.
# @see: https://github.com/calendso/calendso/issues/263
# Required for Vercel hosting - set NEXTAUTH_URL to equal your BASE_URL
@ -66,11 +71,11 @@ CRON_API_KEY='0cc0e6c35519bba620c9360cfe3e68d0'
# Stripe Config
NEXT_PUBLIC_STRIPE_PUBLIC_KEY= # pk_test_...
STRIPE_PRIVATE_KEY= # sk_test_...
STRIPE_CLIENT_ID= # ca_...
STRIPE_WEBHOOK_SECRET= # whsec_...
PAYMENT_FEE_PERCENTAGE=0.005 # Take 0.5% commission
PAYMENT_FEE_FIXED=10 # Take 10 additional cents commission
STRIPE_PRIVATE_KEY= # sk_test_...
STRIPE_CLIENT_ID= # ca_...
STRIPE_WEBHOOK_SECRET= # whsec_...
PAYMENT_FEE_PERCENTAGE=0.005 # Take 0.5% commission
PAYMENT_FEE_FIXED=10 # Take 10 additional cents commission
# Application Key for symmetric encryption and decryption
# must be 32 bytes for AES256 encryption algorithm

View File

@ -20,8 +20,6 @@ jobs:
STRIPE_WEBHOOK_SECRET: ${{ secrets.CI_STRIPE_WEBHOOK_SECRET }}
PAYMENT_FEE_PERCENTAGE: 0.005
PAYMENT_FEE_FIXED: 10
GOOGLE_CLIENT_ID: ${{ secrets.CI_GOOGLE_CLIENT_ID }}
GOOGLE_CLIENT_SECRET: ${{ secrets.CI_GOOGLE_CLIENT_SECRET }}
SAML_DATABASE_URL: postgresql://postgres:@localhost:5432/calendso
SAML_ADMINS: pro@example.com
# NEXTAUTH_URL: xxx

View File

@ -1,8 +1,8 @@
**SAML Registration with Identity Providers**
# SAML Registration with Identity Providers
This guide explains the settings youd need to use to configure SAML with your Identity Provider. Once this is set up you should get an XML metadata file that should then be uploaded on your Cal.com self-hosted instance.
**Note:** Please do not add a trailing slash at the end of the URLs. Create them exactly as shown below.
> **Note:** Please do not add a trailing slash at the end of the URLs. Create them exactly as shown below.
**Assertion consumer service URL / Single Sign-On URL / Destination URL:** [http://localhost:3000/api/auth/saml/callback](http://localhost:3000/api/auth/saml/callback) [Replace this with the URL for your self-hosted Cal instance]

View File

@ -39,5 +39,3 @@ export const identityProviderNameMap: { [key in IdentityProvider]: string } = {
[IdentityProvider.GOOGLE]: "Google",
[IdentityProvider.SAML]: "SAML",
};
export const isGoogleLoginEnabled = !!(process.env.GOOGLE_CLIENT_ID && process.env.GOOGLE_CLIENT_SECRET);

View File

@ -1,17 +1,18 @@
import { IdentityProvider } from "@prisma/client";
import NextAuth, { Session } from "next-auth";
import { Provider } from "next-auth/providers";
import CredentialsProvider from "next-auth/providers/credentials";
import GoogleProvider from "next-auth/providers/google";
import { authenticator } from "otplib";
import { ErrorCode, isGoogleLoginEnabled, verifyPassword } from "@lib/auth";
import { ErrorCode, verifyPassword } from "@lib/auth";
import { symmetricDecrypt } from "@lib/crypto";
import prisma from "@lib/prisma";
import { randomString } from "@lib/random";
import { isSAMLLoginEnabled, samlLoginUrl } from "@lib/saml";
import slugify from "@lib/slugify";
import { IdentityProvider } from ".prisma/client";
import { GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, IS_GOOGLE_LOGIN_ENABLED } from "@server/lib/constants";
const providers: Provider[] = [
CredentialsProvider({
@ -91,11 +92,11 @@ const providers: Provider[] = [
}),
];
if (isGoogleLoginEnabled) {
if (IS_GOOGLE_LOGIN_ENABLED) {
providers.push(
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID || "",
clientSecret: process.env.GOOGLE_CLIENT_SECRET || "",
clientId: GOOGLE_CLIENT_ID,
clientSecret: GOOGLE_CLIENT_SECRET,
})
);
}

5
server/lib/constants.ts Normal file
View File

@ -0,0 +1,5 @@
export const GOOGLE_API_CREDENTIALS = process.env.GOOGLE_API_CREDENTIALS || "{}";
export const { client_id: GOOGLE_CLIENT_ID, client_secret: GOOGLE_CLIENT_SECRET } =
JSON.parse(GOOGLE_API_CREDENTIALS)?.web;
export const GOOGLE_ENABLE_LOGIN = process.env.GOOGLE_ENABLE_LOGIN === "true";
export const IS_GOOGLE_LOGIN_ENABLED = !!(GOOGLE_CLIENT_ID && GOOGLE_CLIENT_SECRET && GOOGLE_ENABLE_LOGIN);

View File

@ -205,18 +205,19 @@ export const viewerTeamsRouter = createProtectedRouter()
message: `Invite failed because there is no corresponding user for ${input.usernameOrEmail}`,
});
// valid email given, create User
await ctx.prisma.user
.create({ data: { email: input.usernameOrEmail, invitedTo: input.teamId } })
.then((invitee) =>
ctx.prisma.membership.create({
data: {
// valid email given, create User and add to team
await ctx.prisma.user.create({
data: {
email: input.usernameOrEmail,
invitedTo: input.teamId,
teams: {
create: {
teamId: input.teamId,
userId: invitee.id,
role: input.role as MembershipRole,
},
})
);
},
},
});
const token: string = randomBytes(32).toString("hex");