Skip to content

Commit

Permalink
refactor(service): users/auth: align identity provider document to en…
Browse files Browse the repository at this point in the history
…tity with intent to create a database migration
  • Loading branch information
restjohn committed Oct 14, 2024
1 parent 09888d7 commit 8ae412b
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 40 deletions.
69 changes: 30 additions & 39 deletions service/src/ingress/identity-providers.adapters.db.mongoose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,34 +15,31 @@ export type CommonIdpSettings = {
newUserEvents?: MageEventId[]
}

export type IdentityProviderDocument = {
export type IdentityProviderDocument = Omit<IdentityProvider, 'id'> & {
_id: ObjectId
name: string
/**
* IDP type maps to an ingress authentication protocol.
*/
type: string
lastUpdated: Date
enabled: boolean
title?: string
settings: CommonIdpSettings & Record<string, any>
textColor?: string
buttonColor?: string
icon?: Buffer
}

export type IdentityProviderModel = mongoose.Model<IdentityProviderDocument>

export const IdentityProviderSchema = new Schema<IdentityProviderDocument>(
{
name: { type: String, required: true },
type: { type: String, required: true },
protocol: { type: String, required: true },
protocolSettings: Schema.Types.Mixed,
userEnrollmentPolicy: {
accountApprovalRequired: { type: Boolean, required: true, default: true },
assignRole: { type: String, required: true },
assignToEvents: { type: [Number], default: [] },
assignToTeams: { type: [String], default: [] },
},
deviceEnrollmentPolicy: {
deviceApprovalRequired: { type: Boolean, required: true, default: true },
},
title: { type: String, required: false },
textColor: { type: String, required: false },
buttonColor: { type: String, required: false },
icon: { type: Buffer, required: false },
enabled: { type: Boolean, default: true },
settings: Schema.Types.Mixed
},
{
timestamps: {
Expand All @@ -55,24 +52,16 @@ export const IdentityProviderSchema = new Schema<IdentityProviderDocument>(
IdentityProviderSchema.index({ name: 1, type: 1 }, { unique: true })

export function idpEntityForDocument(doc: IdentityProviderDocument): IdentityProvider {
const settings = doc.settings || {}
const userEnrollmentPolicy: UserEnrollmentPolicy = {
accountApprovalRequired: !!settings.usersReqAdmin?.enabled,
assignToTeams: doc.settings.newUserTeams || [],
assignToEvents: doc.settings.newUserEvents || [],
}
const deviceEnrollmentPolicy: DeviceEnrollmentPolicy = {
deviceApprovalRequired: !!settings.devicesReqAdmin?.enabled
}
const userEnrollmentPolicy: UserEnrollmentPolicy = { ...doc.userEnrollmentPolicy }
const deviceEnrollmentPolicy: DeviceEnrollmentPolicy = { ...doc.deviceEnrollmentPolicy }
return {
id: doc._id.toHexString(),
name: doc.name,
enabled: doc.enabled,
lastUpdated: doc.lastUpdated,
// TODO: use protocol instance if appropriate
protocol: { name: doc.type },
protocol: doc.protocol,
title: doc.title || doc.name,
protocolSettings: doc.settings,
protocolSettings: { ...doc.protocolSettings },
textColor: doc.textColor,
buttonColor: doc.buttonColor,
icon: doc.icon,
Expand All @@ -82,22 +71,24 @@ export function idpEntityForDocument(doc: IdentityProviderDocument): IdentityPro
}

export function idpDocumentForEntity(entity: Partial<IdentityProvider>): Partial<IdentityProviderDocument> {
// TODO: maybe delegate to protocol to copy settings
const settings = entity.protocolSettings ? { ...entity.protocolSettings } as CommonIdpSettings : undefined
const { userEnrollmentPolicy, deviceEnrollmentPolicy } = entity
if (settings && userEnrollmentPolicy) {
settings.usersReqAdmin = { enabled: !!userEnrollmentPolicy?.accountApprovalRequired }
settings.newUserTeams = userEnrollmentPolicy?.assignToTeams || []
settings.newUserEvents = userEnrollmentPolicy?.assignToEvents || []
}
if (settings && deviceEnrollmentPolicy) {
settings.devicesReqAdmin = { enabled: !!deviceEnrollmentPolicy?.deviceApprovalRequired }
}
const doc = {} as Partial<IdentityProviderDocument>
const entityHasKey = (key: keyof IdentityProvider): boolean => Object.prototype.hasOwnProperty.call(entity, key)
if (entityHasKey('id')) {
doc._id = new mongoose.Types.ObjectId(entity.id)
}
if (entityHasKey('protocol')) {
doc.protocol = entity.protocol
}
if (entityHasKey('protocolSettings')) {
// TODO: maybe delegate to protocol to copy settings
doc.protocolSettings = { ...entity.protocolSettings }
}
if (entityHasKey('userEnrollmentPolicy')) {
doc.userEnrollmentPolicy = { ...entity.userEnrollmentPolicy! }
}
if (entityHasKey('deviceEnrollmentPolicy')) {
doc.deviceEnrollmentPolicy = { ...entity.deviceEnrollmentPolicy! }
}
if (entityHasKey('buttonColor')) {
doc.buttonColor = entity.buttonColor
}
Expand All @@ -114,7 +105,7 @@ export function idpDocumentForEntity(entity: Partial<IdentityProvider>): Partial
doc.name = entity.name
}
if (entityHasKey('protocol')) {
doc.type = entity.protocol?.name
doc.protocol = entity.protocol
}
if (entityHasKey('textColor')) {
doc.textColor = entity.textColor
Expand Down
3 changes: 2 additions & 1 deletion service/src/ingress/local-idp.adapters.db.mongoose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ function documentForEntity(entity: Partial<LocalIdpAccount>): Partial<LocalIdpAc
}

function localIdpSecurityPolicyFromIdenityProvider(localIdp: IdentityProviderDocument): SecurityPolicy {
const settings = localIdp.settings
const settings = localIdp.protocolSettings
return {
accountLock: { ...settings.accountLock },
passwordRequirements: { ...settings.passwordPolicy }
Expand All @@ -232,6 +232,7 @@ export class LocalIdpMongooseRepository implements LocalIdpRepository {
async createLocalAccount(account: LocalIdpAccount): Promise<LocalIdpAccount | LocalIdpDuplicateUsernameError> {
const doc = documentForEntity(account)
const created = await this.LocalIdpAccountModel.create(doc)
// TODO: handle duplicate username error
return entityForDocument(created)
}

Expand Down

0 comments on commit 8ae412b

Please sign in to comment.