Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Oauth Login #279

Open
wants to merge 29 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion .env
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,13 @@ APP_DATABASE_USERNAME="postgres"
APP_DATABASE_PASSWORD="postgres"
APP_DATABASE_DATABASE="postgres"

APP_SECURITY_JWT_SECRET=loafofbread
APP_AUTHORIZATION_JWT_SECRET=loafofbread
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use better jwt secret / certificate


APP_AUTHORIZATION_OAUTH_CLIENT_KEY="ZcSZxYTcWUCsumYZFaPfjBlB6Q7MaFMQ7yIFkukD"
uvulpos marked this conversation as resolved.
Show resolved Hide resolved
APP_AUTHORIZATION_OAUTH_CLIENT_SECRET="C0PPxU4kmv5ZJ8hZdM0Q0uxMANtvfgtL9y3dMlYANs4GOW92k0yQIhaaXoaqN0OEaxdaBzO5oRki1ni7kq4sYjHEnVYhuCqdrjt0G9lRuivkCYjOTJcWXhtEU1bEYHOU"
uvulpos marked this conversation as resolved.
Show resolved Hide resolved
APP_AUTHORIZATION_OAUTH_AUTHORIZATION_URL="http://localhost:9000/application/o/authorize/"
APP_AUTHORIZATION_OAUTH_TOKEN_URL="http://authentik-server:9000/application/o/token/"
APP_AUTHORIZATION_OAUTH_REDIRECT_URL="http://web.localhost/api/v1/oauth/callback"
APP_AUTHORIZATION_OAUTH_USERINFO_URL="http://authentik-server:9000/application/o/userinfo/"
APP_AUTHORIZATION_OAUTH_LOGOUT_URL="http://localhost:9000/application/o/go-svelte/end-session/"
APP_AUTHORIZATION_OAUTH_SCOPES="email openid profile"
Binary file modified .git-assets/app-screenshots/swagger.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .git-assets/app-screenshots/welcome-page.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
@bash ./devops/scripts/utils/install-dependencies.sh

dev: .install-deps ## start debugging in docker compose microservices (auto reload)
@docker compose -f docker-compose.dev.yaml up --abort-on-container-exit backend frontend reverse-proxy
@docker compose -f docker-compose.dev.yaml up --abort-on-container-exit backend frontend reverse-proxy authentik-server authentik-worker

build-full: .install-deps ## build current plattform
@bash ./devops/scripts/build-service/binary.sh
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ services:
AUTHENTIK_POSTGRESQL__NAME: ${APP_DATABASE_DATABASE}-authentik
AUTHENTIK_POSTGRESQL__PASSWORD: ${APP_DATABASE_PASSWORD}
AUTHENTIK_SECRET_KEY: RHRNhMc30ePTXymUm7RXlcs6J7gnK6qXM2+sK+QSLUTpFhbMmMgpNEJgIRRUFPuS/E2sIROIq+5X4ahJ
AUTHENTIK_BOOTSTRAP_EMAIL: [email protected]
AUTHENTIK_BOOTSTRAP_PASSWORD: test
AUTHENTIK_BOOTSTRAP_TOKEN: test

# volumes:
# - ./media:/media
Expand Down Expand Up @@ -88,6 +91,11 @@ services:
AUTHENTIK_POSTGRESQL__NAME: ${APP_DATABASE_DATABASE}-authentik
AUTHENTIK_POSTGRESQL__PASSWORD: ${APP_DATABASE_PASSWORD}
AUTHENTIK_SECRET_KEY: RHRNhMc30ePTXymUm7RXlcs6J7gnK6qXM2+sK+QSLUTpFhbMmMgpNEJgIRRUFPuS/E2sIROIq+5X4ahJ

AUTHENTIK_BOOTSTRAP_EMAIL: [email protected]
AUTHENTIK_BOOTSTRAP_PASSWORD: test
AUTHENTIK_BOOTSTRAP_TOKEN: test

user: root
volumes:
- /var/run/docker.sock:/var/run/docker.sock
Expand Down
6 changes: 3 additions & 3 deletions docker-compose.dev.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# include:
# - path: devops/docker-compose/dev-dependencies/docker-compose.authentik.yaml
# env_file: .env
include:
- path: devops/docker-compose/dev-dependencies/docker-compose.authentik.yaml
env_file: .env

networks:
intranet:
Expand Down
7 changes: 6 additions & 1 deletion services/backend/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ require (
github.com/charmbracelet/lipgloss v0.13.0
github.com/google/uuid v1.6.0 // indirect
github.com/qeesung/image2ascii v1.0.1
github.com/swaggo/swag v1.16.3 // indirect
github.com/swaggo/swag v1.16.3
github.com/uvulpos/go-svelte/authentication-api v0.0.0
github.com/uvulpos/go-svelte/basic-utils v0.0.0
)

replace github.com/uvulpos/go-svelte/basic-utils => ../go_app_modules/basic-utils

replace github.com/uvulpos/go-svelte/authentication-api => ../go_app_modules/authentication-api

require (
github.com/KyleBanks/depth v1.2.1 // indirect
github.com/andybalholm/brotli v1.0.6 // indirect
Expand All @@ -23,6 +26,7 @@ require (
github.com/go-openapi/jsonreference v0.20.2 // indirect
github.com/go-openapi/spec v0.20.11 // indirect
github.com/go-openapi/swag v0.22.4 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
Expand All @@ -43,6 +47,7 @@ require (
github.com/valyala/tcplisten v1.0.0 // indirect
github.com/wayneashleyberry/terminal-dimensions v1.1.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
golang.org/x/oauth2 v0.21.0 // indirect
golang.org/x/tools v0.16.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
Expand Down
8 changes: 8 additions & 0 deletions services/backend/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,12 @@ github.com/gofiber/swagger v1.1.0 h1:ff3rg1fB+Rp5JN/N8jfxTiZtMKe/9tB9QDc79fPiJKQ
github.com/gofiber/swagger v1.1.0/go.mod h1:pRZL0Np35sd+lTODTE5The0G+TMHfNY+oC4hM2/i5m8=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-migrate/migrate/v4 v4.17.1 h1:4zQ6iqL6t6AiItphxJctQb3cFqWiSpMnX7wLTPnnYO4=
github.com/golang-migrate/migrate/v4 v4.17.1/go.mod h1:m8hinFyWBn0SA4QKHuKh175Pm9wjmxj3S2Mia7dbXzM=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
Expand Down Expand Up @@ -168,6 +172,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand Down Expand Up @@ -200,3 +206,5 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
2 changes: 1 addition & 1 deletion services/backend/modd.conf
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@goimports = go run golang.org/x/tools/cmd/goimports

src/**/* !src/assets/frontend/**/* {
src/**/* /app/go_app_modules/**/* !src/assets/frontend/**/* {
prep: swag fmt -g src/web-app/app.go && swag init -g src/web-app/app.go -o swagger-docs
daemon +sigterm: go run src/main.go run
}
9 changes: 9 additions & 0 deletions services/backend/src/assets/assets.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,12 @@ var SvelteFS embed.FS

//go:embed terminal-assets/*
var TerminalFS embed.FS

//go:embed swagger-css/gopher-coffee.gif
var GopherCoffee string

//go:embed swagger-css/logo.png
var Logo string

//go:embed swagger-css/logo-branding.png
var LogoBranding string
3 changes: 2 additions & 1 deletion services/backend/src/assets/swagger-css/defaultmode.go

Large diffs are not rendered by default.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added services/backend/src/assets/swagger-css/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 21 additions & 3 deletions services/backend/src/configuration/variables.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,36 @@ var (
// WEBSERVER
WEBSERVER_DISPLAYNAME = configurationHelper.GetEnvOrDefaultString("WEBSERVER_DISPLAYHOST", "http://web.localhost/")
WEBSERVER_HOST = configurationHelper.GetEnvOrDefaultString("WEBSERVER_HOST", "127.0.0.1")
WEBSERVER_PORT = configurationHelper.GetEnvOrDefaultInt("WEBSERVER_PORT", 3000)
WEBSERVER_PORT = configurationHelper.GetEnvOrDefaultInt("WEBSERVER_PORT", 443)
uvulpos marked this conversation as resolved.
Show resolved Hide resolved
WEBSERVER_SHOW_FRONTEND = configurationHelper.GetEnvOrDefaultBool("WEBSERVER_SHOW_FRONTEND", true)
WEBSERVER_SHOW_SWAGGER = configurationHelper.GetEnvOrDefaultBool("WEBSERVER_SHOW_SWAGGER", true)

// Database
// DATABASE_ADDR = configurationHelper.GetEnvOrDefaultString("DATABASE_ADDR", "127.0.0.1")
DATABASE_ADDR = configurationHelper.GetEnvOrDefaultString("DATABASE_ADDR", "postgres")
DATABASE_PORT = configurationHelper.GetEnvOrDefaultInt("DATABASE_PORT", 5432)
DATABASE_SSL = configurationHelper.GetEnvOrDefaultBool("DATABASE_SSL", false)
DATABASE_USERNAME = configurationHelper.GetEnvOrDefaultString("DATABASE_USERNAME", "postgres")
DATABASE_PASSWORD = configurationHelper.GetEnvOrDefaultString("DATABASE_PASSWORD", "postgres")
DATABASE_DATABASE = configurationHelper.GetEnvOrDefaultString("DATABASE_DATABASE", "postgres")

// Security
SECURITY_JWT_SECRET = configurationHelper.GetEnvOrDefaultString("SECURITY_JWT_SECRET", "loafofbread")
// Oauth
AUTHORIZATION_OAUTH_KEY = configurationHelper.GetEnvOrDefaultString("AUTHORIZATION_OAUTH_CLIENT_KEY", "")
AUTHORIZATION_OAUTH_SECRET = configurationHelper.GetEnvOrDefaultString("AUTHORIZATION_OAUTH_CLIENT_SECRET", "")
AUTHORIZATION_OAUTH_CALLBACK_URL = configurationHelper.GetEnvOrDefaultString("AUTHORIZATION_OAUTH_REDIRECT_URL", "http://web.localhost/api/v1/callback")
AUTHORIZATION_OAUTH_AUTHORIZATION_URL = configurationHelper.GetEnvOrDefaultString("AUTHORIZATION_OAUTH_AUTHORIZATION_URL", "http://localhost:9000/application/o/authorize/")
AUTHORIZATION_OAUTH_TOKEN_URL = configurationHelper.GetEnvOrDefaultString("AUTHORIZATION_OAUTH_TOKEN_URL", "")
AUTHORIZATION_OAUTH_USERINFO_URL = configurationHelper.GetEnvOrDefaultString("AUTHORIZATION_OAUTH_USERINFO_URL", "")
AUTHORIZATION_OAUTH_SCOPES = configurationHelper.GetEnvOrDefaultStringArray("AUTHORIZATION_OAUTH_SCOPES", []string{})
AUTHORIZATION_OAUTH_LOGOUT_URL = configurationHelper.GetEnvOrDefaultString("AUTHORIZATION_OAUTH_LOGOUT_URL", "")

// Certificates
CERTIFICATE_IDENTITY_NAME = configurationHelper.GetEnvOrDefaultString("CERTIFICATE_IDENTITY_NAME", "uVulpos - My Application")
CERTIFICATE_IDENTITY_ORGANIZATION = configurationHelper.GetEnvOrDefaultString("CERTIFICATE_IDENTITY_ORGANIZATION", "The Innovators")
CERTIFICATE_IDENTITY_ORGANIZATION_UNIT = configurationHelper.GetEnvOrDefaultString("CERTIFICATE_IDENTITY_ORGANIZATION_UNIT", "Technical Innovation")
CERTIFICATE_IDENTITY_ORGANIZATION_ADRESS = configurationHelper.GetEnvOrDefaultString("CERTIFICATE_IDENTITY_ORGANIZATION_ADRESS", "Example Street 12a")
CERTIFICATE_IDENTITY_ORGANIZATION_CITY = configurationHelper.GetEnvOrDefaultString("CERTIFICATE_IDENTITY_ORGANIZATION_CITY", "Munich")
CERTIFICATE_IDENTITY_ORGANIZATION_POSTAL_CODE = configurationHelper.GetEnvOrDefaultString("CERTIFICATE_IDENTITY_ORGANIZATION_POSTAL_CODE", "12345")
CERTIFICATE_IDENTITY_ORGANIZATION_POSTAL_STATE = configurationHelper.GetEnvOrDefaultString("CERTIFICATE_IDENTITY_ORGANIZATION_POSTAL_STATE", "Bavaria")
CERTIFICATE_IDENTITY_ORGANIZATION_POSTAL_COUNTRY = configurationHelper.GetEnvOrDefaultString("CERTIFICATE_IDENTITY_ORGANIZATION_POSTAL_COUNTRY", "Germany")
)
13 changes: 0 additions & 13 deletions services/backend/src/helper/check/is_valid_email.go

This file was deleted.

8 changes: 0 additions & 8 deletions services/backend/src/helper/check/is_valid_username.go

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
ALTER TABLE user_sessions DROP CONSTRAINT IF EXISTS created_ip_addr_not_empty_string;
ALTER TABLE user_sessions DROP CONSTRAINT IF EXISTS last_jwt_refresh_ip_addr_not_empty_string;

DROP TABLE IF EXISTS user_sessions;
DROP TABLE IF EXISTS user_identities;
DROP TABLE IF EXISTS users;

DROP TYPE IF EXISTS identity_provider;
uvulpos marked this conversation as resolved.
Show resolved Hide resolved
41 changes: 41 additions & 0 deletions services/backend/src/migrator/migration-files/2_add_user.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
CREATE TYPE identity_provider IF NOT EXISTS AS ENUM ();
ALTER TYPE enum_type ADD VALUE 'Authentik';

CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
username VARCHAR UNIQUE NOT NULL,
display_name VARCHAR NOT NULL,
email VARCHAR NOT NULL,
email_verified VARCHAR NOT NULL
);

CREATE TABLE user_identities (
provider identity_provider NOT NULL,
provider_user_id VARCHAR NOT NULL,
user_id UUID NOT NULL,
PRIMARY KEY (provider, provider_user_id),
FOREIGN KEY (user_id) REFERENCES users (id),
UNIQUE (provider, provider_user_id, user_id)
);

CREATE TABLE user_sessions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL,
useragent_hash VARCHAR CHECK (useragent_hash != ''), -- to prevent at least a bit session hijacking
created TIMESTAMP NOT NULL DEFAULT NOW(),
created_ip_addr VARCHAR DEFAULT NULL,
last_jwt_refresh TIMESTAMP NOT NULL DEFAULT NOW(),
last_jwt_refresh_ip_addr VARCHAR DEFAULT NULL,
FOREIGN KEY (user_id) REFERENCES users (id),
UNIQUE (id, user_id)
);

-- Value can be null, but not empty string
ALTER TABLE user_sessions
ADD CONSTRAINT created_ip_addr_not_empty_string
CHECK (created_ip_addr IS NULL OR (created_ip_addr != ''));

-- Value can be null, but not empty string
ALTER TABLE user_sessions
ADD CONSTRAINT last_jwt_refresh_ip_addr_not_empty_string
CHECK (last_jwt_refresh_ip_addr IS NULL OR (last_jwt_refresh_ip_addr != ''));
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
CREATE TABLE IF NOT EXISTS roles (
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
name VARCHAR UNIQUE NOT NULL,
inherit_from UUID,
FOREIGN KEY (inherit_from) REFERENCES roles(id) ON DELETE SET NULL,
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could be also an array, to inherit from multiple roles (like an admin)

CHECK (inherit_from != id)
);

CREATE TABLE IF NOT EXISTS permissions (
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
name VARCHAR UNIQUE NOT NULL,
description VARCHAR NOT NULL,
identifier VARCHAR UNIQUE NOT NULL
CHECK (identifier != '')
);

CREATE TABLE IF NOT EXISTS role_permissions (
role_id UUID,
permission_id UUID,
FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE,
FOREIGN KEY (permission_id) REFERENCES permissions(id) ON DELETE CASCADE,
PRIMARY KEY (role_id, permission_id)
);

CREATE TABLE IF NOT EXISTS user_roles (
user_id UUID,
role_id UUID,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE,
PRIMARY KEY (user_id, role_id)
);

CREATE OR REPLACE FUNCTION get_user_permissions(p_user_id UUID)
RETURNS JSONB AS $$
BEGIN
RETURN (
WITH RECURSIVE role_hierarchy AS (
-- Base case: Get all roles directly assigned to the user
SELECT
ur.user_id,
r.id AS role_id
FROM user_roles ur
JOIN roles r ON ur.role_id = r.id
WHERE ur.user_id = p_user_id
UNION

-- Recursive case: Get all roles that are inherited from other roles
SELECT
rh.user_id,
r2.id AS role_id
FROM role_hierarchy rh
JOIN roles r1 ON rh.role_id = r1.id
JOIN roles r2 ON r1.inherit_from = r2.id
)
SELECT
jsonb_agg(DISTINCT p.identifier) AS permissions
FROM role_hierarchy rh
JOIN role_permissions rp ON rh.role_id = rp.role_id
JOIN permissions p ON rp.permission_id = p.id
);
END;
$$ LANGUAGE plpgsql;
Loading