Skip to content

Commit

Permalink
refactor(service): users/auth: progress commit
Browse files Browse the repository at this point in the history
  • Loading branch information
restjohn committed Aug 28, 2024
1 parent 22ab9a6 commit bbbabff
Show file tree
Hide file tree
Showing 6 changed files with 248 additions and 72 deletions.
30 changes: 17 additions & 13 deletions service/src/authentication/adapters.authentication.db.mongoose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,25 @@ import crypto from 'crypto'
import mongoose, { Schema } from 'mongoose'
import { UserDocumentExpanded } from '../adapters/users/adapters.users.db.mongoose'
import { UserId } from '../entities/users/entities.users'
import { Session, SessionRepository } from './entities.authentication'

export interface SessionDocument {
token: string
expirationDate: Date
userId?: mongoose.Types.ObjectId | undefined
userId: mongoose.Types.ObjectId
deviceId?: mongoose.Types.ObjectId | undefined
}
export type SessionDocumentExpanded = SessionDocument & {
userId: UserDocumentExpanded
deviceId?: mongoose.Document
}
export type SessionModel = mongoose.Model<SessionDocument>

const SessionSchema = new Schema<SessionDocument, SessionModel>(
{
token: { type: String, required: true },
expirationDate: { type: Date, required: true },
userId: { type: Schema.Types.ObjectId, ref: 'User' },
deviceId: { type: Schema.Types.ObjectId, ref: 'Device' },
expirationDate: { type: Date, required: true },
},
{ versionKey: false }
)
Expand All @@ -29,14 +29,6 @@ const SessionSchema = new Schema<SessionDocument, SessionModel>(
SessionSchema.index({ token: 1 })
SessionSchema.index({ expirationDate: 1 }, { expireAfterSeconds: 0 })

export interface SessionRepository {
readonly model: SessionModel
createOrRefreshSession(userId: UserId, deviceId?: string): Promise<SessionDocumentExpanded>
removeSession(token: string): Promise<void>
removeSessionsForUser(userId: UserId): Promise<number>
removeSessionForDevice(deviceId: string): Promise<number>
}

const populateSessionUserRole: mongoose.PopulateOptions = {
path: 'userId',
populate: 'roleId'
Expand All @@ -46,7 +38,19 @@ export function createSessionRepository(conn: mongoose.Connection, collectionNam
const model = conn.model('Token', SessionSchema, collectionName)
return Object.freeze({
model,
async createOrRefreshSession(userId: UserId, deviceId?: string): Promise<mongoose.HydratedDocument<SessionDocumentExpanded>> {
async findSessionByToken(token: string): Promise<Session | null> {
const doc = await model.findOne({ token }).lean()
if (!doc) {
return null
}
return {
token: doc.token,
expirationDate: doc.expirationDate,
user: doc.userId.toHexString(),
device: doc.deviceId?.toHexString(),
}
},
async createOrRefreshSession(userId: UserId, deviceId?: string): Promise<mongoose.HydratedDocument<Session>> {
const seed = crypto.randomBytes(20)
const token = crypto.createHash('sha256').update(seed).digest('hex')
const query: any = { userId: new mongoose.Types.ObjectId(userId) }
Expand All @@ -68,7 +72,7 @@ export function createSessionRepository(conn: mongoose.Connection, collectionNam
const { deletedCount } = await model.deleteMany({ userId: new mongoose.Types.ObjectId(userId) })
return deletedCount
},
async removeSessionForDevice(deviceId: string): Promise<number> {
async removeSessionsForDevice(deviceId: string): Promise<number> {
const { deletedCount } = await model.deleteMany({ deviceId: new mongoose.Types.ObjectId(deviceId) })
return deletedCount
}
Expand Down
4 changes: 4 additions & 0 deletions service/src/authentication/devices.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

export interface DeviceAuthenticationPolicyService {

}
51 changes: 50 additions & 1 deletion service/src/authentication/entities.authentication.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { Device, DeviceId } from '../entities/devices/entities.devices'
import { MageEventId } from '../entities/events/entities.events'
import { TeamId } from '../entities/teams/entities.teams'
import { UserExpanded, UserId } from '../entities/users/entities.users'

export interface Session {
Expand All @@ -18,5 +20,52 @@ export interface SessionRepository {
createOrRefreshSession(userId: UserId, deviceId?: string): Promise<Session>
removeSession(token: string): Promise<void>
removeSessionsForUser(userId: UserId): Promise<number>
removeSessionForDevice(deviceId: DeviceId): Promise<number>
removeSessionsForDevice(deviceId: DeviceId): Promise<number>
}

/**
* An authentication protocol defines the sequence of messages between a user, a service provider (Mage), and an
* identity provider (Google, Meta, Okta, Auth0, Microsoft, GitHub) necessary to securely inform the service provider
* that the user is valid. Authentication protocols are OpenID Connect, OAuth, SAML, LDAP, and Mage's own local
* password authentication database.
*/
export interface AuthenticationProtocol {
name: string
}

/**
* An identity provider (IDP) is a service maintains user profiles and that Mage trusts to authenticate user
* credentials via a specific authentication protocol. Mage delegates user authentication to identity providers.
* Within Mage, the identity provider implementation maps the provider's user profile/account attributes to a Mage
* user profile.
*/
export interface IdentityProvider {
name: string
title: string
protocol: AuthenticationProtocol
protocolSettings: Record<string, any>
enabled: boolean
lastUpdated: Date
enrollmentPolicy: EnrollmentPolicy
description?: string | null
textColor?: string | null
buttonColor?: string | null
icon?: Buffer | null
}

/**
* Enrollment policy defines rules and effects to apply when a new user establishes a Mage account.
*/
export interface EnrollmentPolicy {
assignToTeams: TeamId[]
assignToEvents: MageEventId[]
requireAccountApproval: boolean
requireDeviceApproval: boolean
}



export interface IdentityProviderRepository {
findById(): Promise<IdentityProvider | null>
findByName(name: string): Promise<IdentityProvider | null>
}
Loading

0 comments on commit bbbabff

Please sign in to comment.