Skip to content

Commit

Permalink
Start reworking auth model
Browse files Browse the repository at this point in the history
  • Loading branch information
StevenWeathers committed Apr 11, 2024
1 parent bec75dd commit 400e860
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 21 deletions.
21 changes: 12 additions & 9 deletions internal/db/auth/oauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package auth

import (
"context"
"database/sql"
"errors"
"fmt"
"time"
Expand Down Expand Up @@ -46,17 +47,16 @@ func (d *Service) OauthValidateNonce(ctx context.Context, nonceId string) error
}

// OauthAuthUser authenticate the oauth user or creates a new user
func (d *Service) OauthAuthUser(ctx context.Context, provider string, email string, emailVerified bool, name string, pictureUrl string) (*thunderdome.User, string, error) {
func (d *Service) OauthAuthUser(ctx context.Context, provider string, sub string, email string, emailVerified bool, name string, pictureUrl string) (*thunderdome.User, string, error) {
var user thunderdome.User

err := d.DB.QueryRowContext(ctx,
`INSERT INTO thunderdome.users (type, provider, email, verified, name, picture_url)
VALUES ('REGISTERED', $1, $2, $3, $4, $5)
ON CONFLICT (provider, lower((email)::text)) DO UPDATE
SET verified = EXCLUDED.verified
RETURNING id, name, email, type, verified, notifications_enabled,
COALESCE(locale, ''), disabled, theme, COALESCE(picture_url, '')`,
provider, email, emailVerified, name, pictureUrl,
`SELECT u.id, u.name, ai.email, u.type, ai.verified, u.notifications_enabled,
COALESCE(u.locale, ''), u.disabled, u.theme, COALESCE(u.picture_url, '')
FROM thunderdome.auth_identity ai
JOIN thunderdome.users u ON u.id = ai.user_id
WHERE ai.provider = $1 AND ai.sub = $2`,
provider, sub,
).Scan(
&user.Id,
&user.Name,
Expand All @@ -69,7 +69,10 @@ func (d *Service) OauthAuthUser(ctx context.Context, provider string, email stri
&user.Theme,
&user.PictureURL,
)
if err != nil {
if err != nil && errors.Is(err, sql.ErrNoRows) {
// @TODO - INSERT NEW USER and Identity
return nil, "", err
} else if err != nil {
return nil, "", err
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,31 @@
-- +goose Up
-- +goose StatementBegin
ALTER TABLE thunderdome.users ADD COLUMN provider TEXT NOT NULL DEFAULT 'internal';
ALTER TABLE thunderdome.users ADD COLUMN picture_url TEXT;
CREATE UNIQUE INDEX IF NOT EXISTS provider_email_unique_idx ON thunderdome.users USING btree (provider,lower((email)::text));
DROP INDEX thunderdome.email_unique_idx;
CREATE TABLE IF NOT EXISTS thunderdome.auth_nonce (
nonce_id character varying(64) NOT NULL PRIMARY KEY,
created_date timestamp with time zone DEFAULT now(),
expire_date timestamp with time zone DEFAULT (now() + '10 minutes'::interval)
);
CREATE TABLE thunderdome.auth_credential (
user_id uuid UNIQUE NOT NULL REFERENCES thunderdome.users(id) ON DELETE CASCADE,
email character varying(320),
password text,
verified boolean DEFAULT false,
mfa_enabled boolean DEFAULT false NOT NULL,
created_date timestamp with time zone NOT NULL DEFAULT now(),
updated_date timestamp with time zone NOT NULL DEFAULT now()
);
CREATE UNIQUE INDEX cred_email_unique_idx ON thunderdome.auth_credential USING btree (lower((email)::text));
CREATE TABLE thunderdome.auth_identity (
user_id uuid NOT NULL REFERENCES thunderdome.users(id) ON DELETE CASCADE,
provider character varying(64) NOT NULL,
sub TEXT NOT NULL,
email character varying(320) NOT NULL,
verified boolean NOT NULL DEFAULT false,
created_date timestamp with time zone NOT NULL DEFAULT now(),
updated_date timestamp with time zone NOT NULL DEFAULT now(),
UNIQUE(provider, sub)
);
ALTER TABLE thunderdome.users ADD COLUMN picture_url TEXT;
CREATE OR REPLACE FUNCTION thunderdome.prune_auth_nonces() RETURNS trigger
LANGUAGE plpgsql
AS $$
Expand All @@ -29,10 +46,10 @@ CREATE TRIGGER prune_auth_nonces AFTER INSERT ON thunderdome.auth_nonce FOR EACH
-- +goose Down
-- +goose StatementBegin
CREATE UNIQUE INDEX IF NOT EXISTS email_unique_idx ON thunderdome.users USING btree (lower((email)::text));
DROP INDEX thunderdome.provider_email_unique_idx;
ALTER TABLE thunderdome.users DROP COLUMN provider;
ALTER TABLE thunderdome.users DROP COLUMN picture_url;
DROP TABLE thunderdome.auth_nonce;
DROP TRIGGER prune_auth_nonces ON thunderdome.auth_nonce;
DROP FUNCTION thunderdome.prune_auth_nonces();
ALTER TABLE thunderdome.users DROP COLUMN picture_url;
DROP TABLE thunderdome.auth_nonce;
DROP TABLE thunderdome.auth_credential;
DROP TABLE thunderdome.auth_identity;
-- +goose StatementEnd
11 changes: 8 additions & 3 deletions internal/oauth/oauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,10 @@ func (s *Service) HandleOAuth2Callback() http.HandlerFunc {
return
}

user, sessionId, userErr := s.authDataSvc.OauthAuthUser(ctx, s.config.ProviderName, claims.Email, claims.EmailVerified, claims.Name, claims.Picture)
user, sessionId, userErr := s.authDataSvc.OauthAuthUser(
ctx, s.config.ProviderName, idToken.Subject, claims.Email,
claims.EmailVerified, claims.Name, claims.Picture,
)
if userErr != nil {
logger.Error("error authenticating oauth user", zap.Error(userErr))
ue := err.Error()
Expand All @@ -154,7 +157,8 @@ func (s *Service) HandleOAuth2Callback() http.HandlerFunc {
}

if scErr := s.cookie.CreateSessionCookie(w, sessionId); scErr != nil {
logger.Error("error creating oauth user session cookie", zap.Error(scErr), zap.String("userId", user.Id))
logger.Error("error creating oauth user session cookie", zap.Error(scErr),
zap.String("userId", user.Id))
w.WriteHeader(http.StatusInternalServerError)
return
}
Expand All @@ -170,7 +174,8 @@ func (s *Service) HandleOAuth2Callback() http.HandlerFunc {
NotificationsEnabled: user.NotificationsEnabled,
Subscribed: subscribedErr == nil,
}); err != nil {
logger.Error("error creating oauth user ui cookie", zap.Error(err), zap.String("userId", user.Id))
logger.Error("error creating oauth user ui cookie", zap.Error(err),
zap.String("userId", user.Id))
w.WriteHeader(http.StatusInternalServerError)
return
}
Expand Down
23 changes: 22 additions & 1 deletion thunderdome/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package thunderdome
import (
"context"
"net/http"
"time"
)

type AuthProviderConfig struct {
Expand All @@ -12,6 +13,26 @@ type AuthProviderConfig struct {
ClientSecret string `mapstructure:"client_secret"`
}

type Credential struct {
UserID string `json:"user_id"`
Email string `json:"email"`
Password string `json:"-"`
Verified bool `json:"verified"`
MFAEnabled bool `json:"mfa_enabled"`
CreatedDate time.Time `json:"created_date"`
UpdatedDate time.Time `json:"updated_date"`
}

type Identity struct {
UserID string `json:"user_id"`
Provider string `json:"provider"`
Sub string `json:"-"`
Email string `json:"email"`
Verified bool `json:"verified"`
CreatedDate time.Time `json:"created_date"`
UpdatedDate time.Time `json:"updated_date"`
}

type AuthProviderSvc interface {
HandleOAuth2Redirect(w http.ResponseWriter, r *http.Request)
HandleOAuth2Callback(w http.ResponseWriter, r *http.Request)
Expand All @@ -21,7 +42,7 @@ type AuthDataSvc interface {
AuthUser(ctx context.Context, UserEmail string, UserPassword string) (*User, string, error)
OauthCreateNonce(ctx context.Context) (string, error)
OauthValidateNonce(ctx context.Context, nonceId string) error
OauthAuthUser(ctx context.Context, provider string, email string, emailVerified bool, name string, pictureUrl string) (*User, string, error)
OauthAuthUser(ctx context.Context, provider string, sub string, email string, emailVerified bool, name string, pictureUrl string) (*User, string, error)
UserResetRequest(ctx context.Context, UserEmail string) (resetID string, UserName string, resetErr error)
UserResetPassword(ctx context.Context, ResetID string, UserPassword string) (UserName string, UserEmail string, resetErr error)
UserUpdatePassword(ctx context.Context, UserID string, UserPassword string) (Name string, Email string, resetErr error)
Expand Down

0 comments on commit 400e860

Please sign in to comment.