Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(auth)!: 拆分getUser为独立的认证系统能力 (#314)
经过进一步考虑,发现getUser应该是一个独立的认证系统能力。有的认证系统不支持创建用户,但是支持查询用户是否存在,比如SSH。有的认证系统支持创建用户,但是不支持查询用户是否存在,比如一些机构的内部认证系统,内部认证系统基本不会给接入者随便查询任意用户的能力。所以getUser应该不是和创建用户的绑定的接口,而是一个独立的能力。
- Loading branch information
Showing
13 changed files
with
233 additions
and
182 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
import { parsePlaceholder } from "@scow/lib-config"; | ||
import { FastifyRequest } from "fastify"; | ||
import ldapjs from "ldapjs"; | ||
import { CreateUserInfo, CreateUserResult } from "src/auth/AuthProvider"; | ||
import { searchOne, useLdap } from "src/auth/ldap/helpers"; | ||
import { modifyPassword } from "src/auth/ldap/password"; | ||
import { AuthConfigSchema, NewUserGroupStrategy } from "src/config/auth"; | ||
import { promisify } from "util"; | ||
|
||
/* | ||
* Apply extra props. | ||
* @param obj the object to apply extra props | ||
* @param extraProps the extraProps config | ||
* @param placeholderObj the object where the values of placeholders ({{ }}) are from | ||
*/ | ||
const applyExtraProps = (obj: object, extraProps: Record<string, string | string[]>, placeholderObj: object) => { | ||
|
||
for (const key in extraProps) { | ||
const value = extraProps[key]; | ||
if (Array.isArray(value)) { | ||
obj[key] = value.map((x) => parsePlaceholder(x, placeholderObj)); | ||
} else { | ||
obj[key] = parsePlaceholder(value, placeholderObj); | ||
} | ||
} | ||
|
||
}; | ||
|
||
export async function createUser( | ||
info: CreateUserInfo, req: FastifyRequest, ldap: NonNullable<AuthConfigSchema["ldap"]>, | ||
): Promise<CreateUserResult> { | ||
|
||
const id = info.id + ldap.addUser.uidStart; | ||
|
||
await useLdap(req.log, ldap)(async (client) => { | ||
const userDn = | ||
`${ldap.addUser.userIdDnKey ?? ldap.attrs.uid}=${info.identityId},` + | ||
`${ldap.addUser.userBase}`; | ||
const userEntry: Record<string, string | string[] | number> = { | ||
[ldap.attrs.uid]: info.identityId, | ||
sn: info.identityId, | ||
loginShell: "/bin/bash", | ||
objectClass: ["inetOrgPerson", "posixAccount", "shadowAccount"], | ||
homeDirectory: parsePlaceholder(ldap.addUser.homeDir, { userId: info.identityId }), | ||
uidNumber: id, | ||
gidNumber: id, | ||
}; | ||
|
||
if (ldap.attrs.name) { | ||
userEntry[ldap.attrs.name] = info.name; | ||
} | ||
|
||
if (ldap.attrs.mail) { | ||
userEntry[ldap.attrs.mail] = info.mail; | ||
} | ||
|
||
// parse attributes | ||
if (ldap.addUser.extraProps) { | ||
applyExtraProps(userEntry, ldap.addUser.extraProps, userEntry); | ||
} | ||
|
||
const add = promisify(client.add.bind(client)); | ||
|
||
|
||
if (ldap.addUser.groupStrategy === NewUserGroupStrategy.newGroupPerUser) { | ||
|
||
req.log.info("ldap.addUser.groupStrategy is newGroupPerUser. Creating new group for the user."); | ||
|
||
const config = ldap.addUser.newGroupPerUser!; | ||
|
||
const groupDn = `${config.groupIdDnKey ?? ldap.attrs.uid}=${info.identityId},${config.groupBase}`; | ||
const groupEntry = { | ||
objectClass: ["posixGroup"], | ||
memberUid: info.identityId, | ||
gidNumber: id, | ||
}; | ||
|
||
userEntry["gidNumber"] = id; | ||
|
||
if (config.extraProps) { | ||
applyExtraProps(groupEntry, config.extraProps, userEntry); | ||
} | ||
|
||
req.log.info("Adding group %s with entry info %o", groupDn, groupEntry); | ||
await add(groupDn, groupEntry); | ||
|
||
} | ||
|
||
if (ldap.addUser.groupStrategy === NewUserGroupStrategy.oneGroupForAllUsers) { | ||
const config = ldap.addUser.oneGroupForAllUsers!; | ||
|
||
req.log.info("ldap.addUser.groupStrategy is one-group-for-all-users."); | ||
req.log.info("Using existing group %s for the user", config.gidNumber); | ||
|
||
userEntry["gidNumber"] = config.gidNumber; | ||
} | ||
|
||
req.log.info("Adding people %s with entry info %o", userDn, userEntry); | ||
await add(userDn, userEntry); | ||
|
||
// set password as admin user | ||
await modifyPassword(userDn, undefined, info.password, client); | ||
|
||
// Add user to ldap group | ||
const addUserToLdapGroup = ldap.addUser.addUserToLdapGroup; | ||
|
||
if (addUserToLdapGroup) { | ||
// get existing members | ||
req.log.info("Adding %s to group %s", userDn, addUserToLdapGroup); | ||
|
||
const members = await searchOne(req.log, client, addUserToLdapGroup, { | ||
attributes: ["member"], | ||
}, (entry) => { | ||
const member = entry.attributes.find((x) => x.json.type === "member"); | ||
if (!member) { | ||
return undefined; | ||
} | ||
|
||
return { members: member.json.vals }; | ||
}); | ||
|
||
if (!members) { | ||
req.log.error("Didn't find LDAP group %s", addUserToLdapGroup); | ||
throw { code: "INTERNAL_ERROR" }; | ||
} | ||
|
||
// add the dn of the new user to the value | ||
const modify = promisify(client.modify.bind(client)); | ||
await modify(addUserToLdapGroup, new ldapjs.Change({ | ||
operation: "add", | ||
modification: { | ||
"member": members.members.concat(userDn), | ||
}, | ||
})); | ||
} | ||
|
||
|
||
}); | ||
|
||
return "OK"; | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.