@authup/server-core 1.0.0-beta.60 → 1.0.0-beta.62
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/database/domains/client-scope/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/client-scope/entity.mjs +16 -8
- package/dist/adapters/database/domains/client-scope/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/identity-provider-account/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/identity-provider-account/entity.mjs +1 -1
- package/dist/adapters/database/domains/identity-provider-account/entity.mjs.map +1 -1
- package/dist/adapters/database/migrations/mysql/1786631686318-SortIndexesAndAccountUniqueness.d.ts +50 -0
- package/dist/adapters/database/migrations/mysql/1786631686318-SortIndexesAndAccountUniqueness.d.ts.map +1 -0
- package/dist/adapters/database/migrations/mysql/1786631686318-SortIndexesAndAccountUniqueness.mjs +86 -0
- package/dist/adapters/database/migrations/mysql/1786631686318-SortIndexesAndAccountUniqueness.mjs.map +1 -0
- package/dist/adapters/database/migrations/postgres/1786631686318-SortIndexesAndAccountUniqueness.d.ts +42 -0
- package/dist/adapters/database/migrations/postgres/1786631686318-SortIndexesAndAccountUniqueness.d.ts.map +1 -0
- package/dist/adapters/database/migrations/postgres/1786631686318-SortIndexesAndAccountUniqueness.mjs +80 -0
- package/dist/adapters/database/migrations/postgres/1786631686318-SortIndexesAndAccountUniqueness.mjs.map +1 -0
- package/dist/adapters/http/adapters/oauth2/grant-types/utils/credentials.mjs +1 -1
- package/dist/adapters/http/adapters/oauth2/grant-types/utils/guess.mjs +1 -1
- package/dist/adapters/http/controllers/entities/client/module.mjs +2 -2
- package/dist/adapters/http/controllers/entities/identity-provider/module.d.ts +12 -8
- package/dist/adapters/http/controllers/entities/identity-provider/module.d.ts.map +1 -1
- package/dist/adapters/http/controllers/entities/identity-provider/module.mjs +137 -88
- package/dist/adapters/http/controllers/entities/identity-provider/module.mjs.map +1 -1
- package/dist/adapters/http/controllers/entities/identity-provider/types.d.ts +7 -5
- package/dist/adapters/http/controllers/entities/identity-provider/types.d.ts.map +1 -1
- package/dist/adapters/http/controllers/entities/realm/module.mjs +2 -2
- package/dist/adapters/http/controllers/entities/session/module.mjs +2 -2
- package/dist/adapters/http/controllers/entities/user/module.mjs +2 -2
- package/dist/adapters/http/controllers/entities/user-authenticator/module.mjs +2 -2
- package/dist/adapters/http/controllers/workflows/authorize/module.d.ts.map +1 -1
- package/dist/adapters/http/controllers/workflows/authorize/module.mjs +9 -5
- package/dist/adapters/http/controllers/workflows/authorize/module.mjs.map +1 -1
- package/dist/adapters/http/controllers/workflows/token/utils/extract.mjs +2 -1
- package/dist/adapters/http/controllers/workflows/token/utils/extract.mjs.map +1 -1
- package/dist/adapters/http/middleware/built-in/assets.mjs +1 -1
- package/dist/adapters/http/request/helpers/param-id.d.ts.map +1 -1
- package/dist/adapters/http/request/helpers/param-id.mjs +2 -1
- package/dist/adapters/http/request/helpers/param-id.mjs.map +1 -1
- package/dist/adapters/http/ui/account-console/module.mjs +1 -1
- package/dist/adapters/http/ui/auth-console/http-client.mjs +1 -1
- package/dist/adapters/http/ui/auth-console/module.mjs +1 -1
- package/dist/adapters/http/ui/console-packages/module.d.ts +1 -1
- package/dist/adapters/http/ui/console-packages/module.mjs +2 -2
- package/dist/adapters/http/ui/console-packages/module.mjs.map +1 -1
- package/dist/adapters/http/ui/shared/html.d.ts.map +1 -1
- package/dist/adapters/http/ui/shared/html.mjs +1 -0
- package/dist/adapters/http/ui/shared/html.mjs.map +1 -1
- package/dist/app/index.mjs +3 -1
- package/dist/app/modules/config/read/env.mjs +1 -1
- package/dist/app/modules/database/repositories/event/repository.d.ts +2 -2
- package/dist/app/modules/database/repositories/event/repository.d.ts.map +1 -1
- package/dist/app/modules/database/repositories/event/repository.mjs +23 -6
- package/dist/app/modules/database/repositories/event/repository.mjs.map +1 -1
- package/dist/app/modules/database/repositories/identity-provider-account/repository.d.ts.map +1 -1
- package/dist/app/modules/database/repositories/identity-provider-account/repository.mjs +9 -1
- package/dist/app/modules/database/repositories/identity-provider-account/repository.mjs.map +1 -1
- package/dist/app/modules/http/modules/controller.d.ts.map +1 -1
- package/dist/app/modules/http/modules/controller.mjs +18 -6
- package/dist/app/modules/http/modules/controller.mjs.map +1 -1
- package/dist/app/modules/identity/constants.d.ts +2 -1
- package/dist/app/modules/identity/constants.d.ts.map +1 -1
- package/dist/app/modules/identity/constants.mjs +1 -0
- package/dist/app/modules/identity/constants.mjs.map +1 -1
- package/dist/app/modules/identity/index.mjs +3 -1
- package/dist/app/modules/identity/module.d.ts.map +1 -1
- package/dist/app/modules/identity/module.mjs +13 -3
- package/dist/app/modules/identity/module.mjs.map +1 -1
- package/dist/app/modules/identity/repositories/constants.d.ts +4 -0
- package/dist/app/modules/identity/repositories/constants.d.ts.map +1 -0
- package/dist/app/modules/identity/repositories/constants.mjs +12 -0
- package/dist/app/modules/identity/repositories/constants.mjs.map +1 -0
- package/dist/app/modules/identity/repositories/index.d.ts +1 -0
- package/dist/app/modules/identity/repositories/index.d.ts.map +1 -1
- package/dist/app/modules/identity/repositories/index.mjs +3 -1
- package/dist/app/modules/identity/repositories/provider/index.d.ts +1 -0
- package/dist/app/modules/identity/repositories/provider/index.d.ts.map +1 -1
- package/dist/app/modules/identity/repositories/provider/index.mjs +2 -1
- package/dist/app/modules/identity/repositories/provider/link.d.ts +9 -0
- package/dist/app/modules/identity/repositories/provider/link.d.ts.map +1 -0
- package/dist/app/modules/identity/repositories/provider/link.mjs +34 -0
- package/dist/app/modules/identity/repositories/provider/link.mjs.map +1 -0
- package/dist/app/modules/identity/repositories/user.d.ts +1 -0
- package/dist/app/modules/identity/repositories/user.d.ts.map +1 -1
- package/dist/app/modules/identity/repositories/user.mjs +3 -0
- package/dist/app/modules/identity/repositories/user.mjs.map +1 -1
- package/dist/app/modules/index.mjs +3 -1
- package/dist/app/modules/oauth2/repositories/authorize/state/repository.d.ts +1 -2
- package/dist/app/modules/oauth2/repositories/authorize/state/repository.d.ts.map +1 -1
- package/dist/app/modules/oauth2/repositories/authorize/state/repository.mjs +7 -16
- package/dist/app/modules/oauth2/repositories/authorize/state/repository.mjs.map +1 -1
- package/dist/app/modules/runtime/module.mjs +2 -2
- package/dist/cli/commands/migration.mjs +1 -1
- package/dist/core/entities/client-scope/schema.d.ts.map +1 -1
- package/dist/core/entities/client-scope/schema.mjs +16 -1
- package/dist/core/entities/client-scope/schema.mjs.map +1 -1
- package/dist/core/entities/event/constants.d.ts +9 -0
- package/dist/core/entities/event/constants.d.ts.map +1 -1
- package/dist/core/entities/event/constants.mjs +9 -1
- package/dist/core/entities/event/constants.mjs.map +1 -1
- package/dist/core/entities/event/index.mjs +2 -2
- package/dist/core/entities/event/types.d.ts +11 -2
- package/dist/core/entities/event/types.d.ts.map +1 -1
- package/dist/core/entities/identity-provider-account/types.d.ts +6 -0
- package/dist/core/entities/identity-provider-account/types.d.ts.map +1 -1
- package/dist/core/entities/identity-provider-account/types.mjs.map +1 -1
- package/dist/core/entities/index.mjs +2 -2
- package/dist/core/identity/entities/user/types.d.ts +1 -0
- package/dist/core/identity/entities/user/types.d.ts.map +1 -1
- package/dist/core/identity/index.mjs +12 -11
- package/dist/core/identity/provider/account/constants.d.ts +10 -0
- package/dist/core/identity/provider/account/constants.d.ts.map +1 -0
- package/dist/core/identity/provider/account/constants.mjs +16 -0
- package/dist/core/identity/provider/account/constants.mjs.map +1 -0
- package/dist/core/identity/provider/account/index.d.ts +1 -0
- package/dist/core/identity/provider/account/index.d.ts.map +1 -1
- package/dist/core/identity/provider/account/index.mjs +2 -1
- package/dist/core/identity/provider/account/module.d.ts +3 -0
- package/dist/core/identity/provider/account/module.d.ts.map +1 -1
- package/dist/core/identity/provider/account/module.mjs +54 -27
- package/dist/core/identity/provider/account/module.mjs.map +1 -1
- package/dist/core/identity/provider/account/types.d.ts +42 -0
- package/dist/core/identity/provider/account/types.d.ts.map +1 -1
- package/dist/core/identity/provider/authentication/index.mjs +1 -1
- package/dist/core/identity/provider/authentication/protocols/oauth2/module.d.ts +18 -0
- package/dist/core/identity/provider/authentication/protocols/oauth2/module.d.ts.map +1 -1
- package/dist/core/identity/provider/authentication/protocols/oauth2/module.mjs +55 -2
- package/dist/core/identity/provider/authentication/protocols/oauth2/module.mjs.map +1 -1
- package/dist/core/identity/provider/authentication/protocols/oauth2/types.d.ts +2 -0
- package/dist/core/identity/provider/authentication/protocols/oauth2/types.d.ts.map +1 -1
- package/dist/core/identity/provider/authentication/protocols/open-id/module.d.ts +0 -3
- package/dist/core/identity/provider/authentication/protocols/open-id/module.d.ts.map +1 -1
- package/dist/core/identity/provider/authentication/protocols/open-id/module.mjs +0 -17
- package/dist/core/identity/provider/authentication/protocols/open-id/module.mjs.map +1 -1
- package/dist/core/identity/provider/index.mjs +12 -11
- package/dist/core/index.mjs +15 -12
- package/dist/core/oauth2/authorization/code-request/verifier/module.d.ts.map +1 -1
- package/dist/core/oauth2/authorization/code-request/verifier/module.mjs +9 -2
- package/dist/core/oauth2/authorization/code-request/verifier/module.mjs.map +1 -1
- package/dist/core/oauth2/authorization/state/module.mjs +1 -2
- package/dist/core/oauth2/authorization/state/module.mjs.map +1 -1
- package/dist/core/oauth2/authorization/state/types.d.ts +5 -2
- package/dist/core/oauth2/authorization/state/types.d.ts.map +1 -1
- package/dist/core/oauth2/end-session/service.d.ts.map +1 -1
- package/dist/core/oauth2/end-session/service.mjs +1 -0
- package/dist/core/oauth2/end-session/service.mjs.map +1 -1
- package/dist/core/oauth2/federated-login/index.d.ts +3 -0
- package/dist/core/oauth2/federated-login/index.d.ts.map +1 -0
- package/dist/core/oauth2/federated-login/index.mjs +6 -0
- package/dist/core/oauth2/federated-login/module.d.ts +20 -0
- package/dist/core/oauth2/federated-login/module.d.ts.map +1 -0
- package/dist/core/oauth2/federated-login/module.mjs +137 -0
- package/dist/core/oauth2/federated-login/module.mjs.map +1 -0
- package/dist/core/oauth2/federated-login/types.d.ts +138 -0
- package/dist/core/oauth2/federated-login/types.d.ts.map +1 -0
- package/dist/core/oauth2/federated-login/types.mjs +31 -0
- package/dist/core/oauth2/federated-login/types.mjs.map +1 -0
- package/dist/core/oauth2/index.d.ts +1 -0
- package/dist/core/oauth2/index.d.ts.map +1 -1
- package/dist/core/oauth2/index.mjs +4 -1
- package/dist/core/provisioning/entities/policy/validator.d.ts.map +1 -1
- package/dist/core/provisioning/entities/policy/validator.mjs +2 -1
- package/dist/core/provisioning/entities/policy/validator.mjs.map +1 -1
- package/dist/core/provisioning/entities/realm/wildcard-validator.d.ts.map +1 -1
- package/dist/core/provisioning/entities/realm/wildcard-validator.mjs +2 -1
- package/dist/core/provisioning/entities/realm/wildcard-validator.mjs.map +1 -1
- package/dist/core/security/policy/evaluator.mjs.map +1 -1
- package/dist/index.mjs +3 -1
- package/dist/node_modules/@ebec/core/dist/index.mjs +130 -0
- package/dist/node_modules/@ebec/core/dist/index.mjs.map +1 -0
- package/dist/swagger.json +146 -18
- package/dist/utils/error.d.ts.map +1 -1
- package/dist/utils/error.mjs +5 -6
- package/dist/utils/error.mjs.map +1 -1
- package/package.json +28 -28
|
@@ -5,9 +5,10 @@ import { RECORD_QUERY_PARAMETERS, describeQuerySchema } from "../../../../../cor
|
|
|
5
5
|
import { identityProviderSchema } from "../../../../../core/entities/identity-provider/schema.mjs";
|
|
6
6
|
import { decodeQuery } from "../../../../../core/query/module.mjs";
|
|
7
7
|
import { OAuth2AuthorizationCodeRequestValidator } from "../../../../../core/oauth2/authorization/code-request/validator.mjs";
|
|
8
|
-
import { toIdentityPolicyData } from "../../../../../core/identity/permission/identity-policy-data.mjs";
|
|
9
|
-
import { isIdentityProviderAccountAlreadyLinkedError } from "../../../../../core/identity/provider/account/error.mjs";
|
|
10
8
|
import { createIdentityProviderOAuth2Authenticator } from "../../../../../core/identity/provider/authentication/factory.mjs";
|
|
9
|
+
import { describeError } from "../../../../../utils/error.mjs";
|
|
10
|
+
import { resolveURL } from "../../../../../utils/url.mjs";
|
|
11
|
+
import "../../../../../utils/index.mjs";
|
|
11
12
|
import "../../../../../core/index.mjs";
|
|
12
13
|
import { useRequestPermissionEvaluator } from "../../../request/permission/helper.mjs";
|
|
13
14
|
import { useRequestIdentityOrFail } from "../../../request/helpers/identity.mjs";
|
|
@@ -15,17 +16,17 @@ import { buildActorContext } from "../../../request/helpers/actor.mjs";
|
|
|
15
16
|
import { getBodyRealmID } from "../../../request/helpers/body-realm-id.mjs";
|
|
16
17
|
import { getRequestParamID, useRequestParamID } from "../../../request/helpers/param-id.mjs";
|
|
17
18
|
import { applyRouteRealmIDToBody, getRequestRealmID } from "../../../request/helpers/realm-id.mjs";
|
|
19
|
+
import { useRequestEventContext } from "../../../request/event-context.mjs";
|
|
18
20
|
import "../../../request/index.mjs";
|
|
19
21
|
import { ForceLoggedInMiddleware } from "../../../middleware/built-in/loggedin/module.mjs";
|
|
20
|
-
import {
|
|
21
|
-
import { resolveURL } from "../../../../../utils/url.mjs";
|
|
22
|
-
import "../../../../../utils/index.mjs";
|
|
22
|
+
import { renderAuthConsolePage } from "../../../ui/auth-console/module.mjs";
|
|
23
23
|
import "../../../middleware/index.mjs";
|
|
24
|
-
import
|
|
25
|
-
import {
|
|
24
|
+
import "../../../ui/index.mjs";
|
|
25
|
+
import { ValidatorGroup, base64URLDecode, isObject, isUUID } from "@authup/kit";
|
|
26
|
+
import { EventName, EventRefType, EventScope, IdentityProviderAttributesValidator, IdentityProviderValidator, IdentityType, PermissionName, buildIdentityProviderAuthorizeCallbackPath, isOAuth2IdentityProvider, isOpenIDIdentityProvider } from "@authup/core-kit";
|
|
26
27
|
import { BuiltInPolicyType, definePolicyData } from "@authup/access";
|
|
27
28
|
import { BadRequestError, EntityNotFoundError } from "@authup/errors";
|
|
28
|
-
import {
|
|
29
|
+
import { OAuth2RequestError } from "@authup/specs";
|
|
29
30
|
import { URL } from "node:url";
|
|
30
31
|
import { getRequestHeader, getRequestIP, sendRedirect } from "routup";
|
|
31
32
|
import { readRequestBody } from "@routup/basic/body";
|
|
@@ -49,27 +50,23 @@ function _ts_param(paramIndex, decorator) {
|
|
|
49
50
|
var IdentityProviderController = class {
|
|
50
51
|
options;
|
|
51
52
|
repository;
|
|
52
|
-
realmRepository;
|
|
53
|
-
clientRepository;
|
|
54
53
|
accountManager;
|
|
54
|
+
linkStore;
|
|
55
55
|
codeRequestVerifier;
|
|
56
56
|
codeRequestValidator;
|
|
57
57
|
stateManager;
|
|
58
|
-
|
|
59
|
-
accessPolicyEvaluator;
|
|
58
|
+
loginService;
|
|
60
59
|
eventService;
|
|
61
60
|
logger;
|
|
62
61
|
constructor(ctx) {
|
|
63
62
|
this.options = ctx.options;
|
|
64
63
|
this.repository = ctx.repository;
|
|
65
|
-
this.realmRepository = ctx.realmRepository;
|
|
66
|
-
this.clientRepository = ctx.clientRepository;
|
|
67
64
|
this.accountManager = ctx.accountManager;
|
|
68
|
-
this.
|
|
65
|
+
this.linkStore = ctx.linkStore;
|
|
69
66
|
this.codeRequestVerifier = ctx.codeRequestVerifier;
|
|
70
67
|
this.codeRequestValidator = new OAuth2AuthorizationCodeRequestValidator();
|
|
71
68
|
this.stateManager = ctx.stateManager;
|
|
72
|
-
this.
|
|
69
|
+
this.loginService = ctx.loginService;
|
|
73
70
|
this.eventService = ctx.eventService;
|
|
74
71
|
this.logger = ctx.logger;
|
|
75
72
|
}
|
|
@@ -152,22 +149,20 @@ var IdentityProviderController = class {
|
|
|
152
149
|
const id = useRequestParamID(event);
|
|
153
150
|
const entity = await this.resolve(id);
|
|
154
151
|
if (!isOAuth2IdentityProvider(entity) && !isOpenIDIdentityProvider(entity)) throw new BadRequestError("Only an identity-provider based on the oauth protocol supports authorize redirect.");
|
|
155
|
-
|
|
156
|
-
let codeRequest;
|
|
152
|
+
if (!entity.enabled) throw new BadRequestError("The identity provider is not enabled.");
|
|
157
153
|
const query = useRequestQuery(event);
|
|
158
|
-
if (typeof query.codeRequest
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
}
|
|
165
|
-
const codeRequestValidated = await this.codeRequestValidator.run(codeRequestDecoded);
|
|
166
|
-
const data = await this.codeRequestVerifier.verify(codeRequestValidated);
|
|
167
|
-
if (data.client.realmId && entity.realmId && entity.realmId !== data.client.realmId) throw OAuth2RequestError.malformed("The provider and client realm do not match.");
|
|
168
|
-
codeRequest = data.data;
|
|
154
|
+
if (typeof query.codeRequest !== "string") throw OAuth2RequestError.malformed("A federated login requires an authorization code request.");
|
|
155
|
+
let codeRequestDecoded;
|
|
156
|
+
try {
|
|
157
|
+
codeRequestDecoded = JSON.parse(base64URLDecode(query.codeRequest));
|
|
158
|
+
} catch {
|
|
159
|
+
throw OAuth2RequestError.malformed("The code request is malformed and can not be parsed.");
|
|
169
160
|
}
|
|
170
|
-
const
|
|
161
|
+
const codeRequestValidated = await this.codeRequestValidator.run(codeRequestDecoded);
|
|
162
|
+
const data = await this.codeRequestVerifier.verify(codeRequestValidated);
|
|
163
|
+
if (data.client.realmId && entity.realmId && entity.realmId !== data.client.realmId) throw OAuth2RequestError.malformed("The provider and client realm do not match.");
|
|
164
|
+
const authenticator = this.buildProviderAuthenticator(entity);
|
|
165
|
+
const state = await this.saveAuthorizationState(event, { codeRequest: data.data });
|
|
171
166
|
return sendRedirect(event, authenticator.buildRedirectURL({ state }));
|
|
172
167
|
}
|
|
173
168
|
async linkRequest(_id, event) {
|
|
@@ -192,50 +187,43 @@ var IdentityProviderController = class {
|
|
|
192
187
|
const data = await this.verifyAuthorizationState(event);
|
|
193
188
|
const { link } = data;
|
|
194
189
|
if (link) return this.completeLink(event, entity, data, link);
|
|
195
|
-
if (
|
|
196
|
-
const { code } = useRequestQuery(event);
|
|
197
|
-
if (typeof
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
if (data.codeRequest?.client_id) {
|
|
201
|
-
const client = await this.clientRepository.findOneByIdOrName(data.codeRequest.client_id, data.codeRequest.realm_id);
|
|
202
|
-
if (client?.accessPolicyId) {
|
|
203
|
-
let allowed = false;
|
|
204
|
-
const subject = toIdentityPolicyData({
|
|
205
|
-
type: IdentityType.USER,
|
|
206
|
-
data: {
|
|
207
|
-
...user,
|
|
208
|
-
realm
|
|
209
|
-
}
|
|
210
|
-
});
|
|
211
|
-
if (this.accessPolicyEvaluator && subject) allowed = await this.accessPolicyEvaluator.evaluate(client.accessPolicyId, subject);
|
|
212
|
-
if (!allowed) {
|
|
213
|
-
const url = this.buildHostedAuthorizeURL(data.codeRequest);
|
|
214
|
-
url.searchParams.set("error", OAuth2ErrorCode.ACCESS_DENIED);
|
|
215
|
-
return sendRedirect(event, url.href);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
190
|
+
if (!data.codeRequest) throw OAuth2RequestError.malformed("The state carries no authorization code request.");
|
|
191
|
+
const { code, error } = useRequestQuery(event);
|
|
192
|
+
if (typeof error === "string" && error.length > 0) {
|
|
193
|
+
this.logger?.info(`The identity provider ${entity.id} answered the authorization with ${JSON.stringify(error.slice(0, 64))}.`);
|
|
194
|
+
return sendRedirect(event, this.buildHostedAuthorizeURL(data.codeRequest).href);
|
|
218
195
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
...user,
|
|
228
|
-
realm
|
|
196
|
+
if (typeof code !== "string" || code.length === 0) throw new BadRequestError("The authorization code is missing.");
|
|
197
|
+
const result = await this.loginService.complete({
|
|
198
|
+
provider: entity,
|
|
199
|
+
codeRequest: data.codeRequest,
|
|
200
|
+
code,
|
|
201
|
+
request: {
|
|
202
|
+
ipAddress: getRequestIP(event),
|
|
203
|
+
userAgent: getRequestHeader(event, "user-agent")
|
|
229
204
|
}
|
|
230
|
-
}
|
|
231
|
-
if (
|
|
232
|
-
const url = this.buildHostedAuthorizeURL(
|
|
233
|
-
url.searchParams.set("
|
|
205
|
+
});
|
|
206
|
+
if (result.kind === "refused") {
|
|
207
|
+
const url = this.buildHostedAuthorizeURL(result.codeRequest);
|
|
208
|
+
if (result.error) url.searchParams.set("error", result.error);
|
|
234
209
|
return sendRedirect(event, url.href);
|
|
235
210
|
}
|
|
236
|
-
const url = new URL(
|
|
237
|
-
url.searchParams.set("code",
|
|
238
|
-
|
|
211
|
+
const url = new URL(result.redirectUri);
|
|
212
|
+
url.searchParams.set("code", result.code);
|
|
213
|
+
if (result.state) url.searchParams.set("state", result.state);
|
|
214
|
+
if (url.protocol === "http:" || url.protocol === "https:") return sendRedirect(event, url.href);
|
|
215
|
+
const payload = {
|
|
216
|
+
redirect: url.href,
|
|
217
|
+
authorizeUrl: this.buildHostedAuthorizeURL(result.codeRequest).href,
|
|
218
|
+
client: result.client
|
|
219
|
+
};
|
|
220
|
+
return renderAuthConsolePage(event, {
|
|
221
|
+
url: buildIdentityProviderAuthorizeCallbackPath(entity.id),
|
|
222
|
+
payload: {
|
|
223
|
+
config: { baseURL: this.options.baseURL },
|
|
224
|
+
data: payload
|
|
225
|
+
}
|
|
226
|
+
});
|
|
239
227
|
}
|
|
240
228
|
async write(event, options = {}) {
|
|
241
229
|
let group;
|
|
@@ -311,32 +299,79 @@ var IdentityProviderController = class {
|
|
|
311
299
|
const { code } = useRequestQuery(event);
|
|
312
300
|
try {
|
|
313
301
|
if (link.providerId !== provider.id || !provider.enabled) throw new BadRequestError("The identity provider is not available for account linking.");
|
|
314
|
-
if (!state.ip || !state.userAgent) throw new BadRequestError("The account link request is not bound to a browser.");
|
|
315
302
|
if (typeof code !== "string" || code.length === 0) throw new BadRequestError("The authorization code is missing.");
|
|
316
303
|
const identity = await this.buildProviderAuthenticator(provider).resolveIdentity({ code });
|
|
317
|
-
|
|
318
|
-
await this.
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
actorType: IdentityType.USER,
|
|
325
|
-
actorId: account.userId,
|
|
326
|
-
requestIpAddress: getRequestIP(event) ?? null,
|
|
327
|
-
requestUserAgent: getRequestHeader(event, "user-agent") ?? null,
|
|
328
|
-
data: {
|
|
329
|
-
providerId: provider.id,
|
|
330
|
-
providerName: provider.name
|
|
331
|
-
}
|
|
304
|
+
if (!identity.id) throw new BadRequestError("The identity provider returned no subject.");
|
|
305
|
+
const handle = await this.linkStore.save({
|
|
306
|
+
providerId: provider.id,
|
|
307
|
+
userId: link.userId,
|
|
308
|
+
providerUserId: identity.id,
|
|
309
|
+
providerUserName: this.pickIdentityCandidate(identity, "name"),
|
|
310
|
+
providerUserEmail: this.pickIdentityCandidate(identity, "email")
|
|
332
311
|
});
|
|
333
|
-
url.searchParams.set("
|
|
312
|
+
url.searchParams.set("linkHandle", handle);
|
|
313
|
+
url.searchParams.set("provider", provider.id);
|
|
334
314
|
} catch (e) {
|
|
335
315
|
this.logger?.error(describeError(e, "The identity-provider account link failed."));
|
|
336
|
-
url.searchParams.set("linkError",
|
|
316
|
+
url.searchParams.set("linkError", "link_failed");
|
|
337
317
|
}
|
|
338
318
|
return sendRedirect(event, url.href);
|
|
339
319
|
}
|
|
320
|
+
/**
|
|
321
|
+
* The bearer-authenticated half of the link (issue #3439): the account
|
|
322
|
+
* row is written here, for the AUTHENTICATED user, never in the callback.
|
|
323
|
+
*/ async confirmLink(_id, _data, event) {
|
|
324
|
+
const id = useRequestParamID(event);
|
|
325
|
+
const provider = await this.resolve(id);
|
|
326
|
+
if (!isOAuth2IdentityProvider(provider) && !isOpenIDIdentityProvider(provider)) throw new BadRequestError("Only an identity-provider based on the oauth protocol supports account linking.");
|
|
327
|
+
if (!provider.enabled) throw new BadRequestError("The identity provider is not enabled.");
|
|
328
|
+
const identity = useRequestIdentityOrFail(event);
|
|
329
|
+
if (identity.type !== IdentityType.USER) throw new BadRequestError("Only a user can link an identity provider account.");
|
|
330
|
+
const body = await readRequestBody(event);
|
|
331
|
+
const handle = isObject(body) ? body.handle : void 0;
|
|
332
|
+
if (typeof handle !== "string" || handle.length === 0) throw new BadRequestError("The account link handle is missing.");
|
|
333
|
+
const link = await this.linkStore.consume(handle);
|
|
334
|
+
if (!link) throw new BadRequestError("The account link request is unknown or expired.");
|
|
335
|
+
if (link.userId !== identity.id || link.providerId !== provider.id) throw new BadRequestError("The account link request does not belong to the authenticated user.");
|
|
336
|
+
const account = await this.accountManager.link({
|
|
337
|
+
id: link.providerUserId,
|
|
338
|
+
attributeCandidates: {
|
|
339
|
+
name: [link.providerUserName],
|
|
340
|
+
email: [link.providerUserEmail]
|
|
341
|
+
},
|
|
342
|
+
data: {},
|
|
343
|
+
provider
|
|
344
|
+
}, identity.id);
|
|
345
|
+
const requestContext = useRequestEventContext();
|
|
346
|
+
await this.eventService?.record({
|
|
347
|
+
scope: EventScope.IDENTITY,
|
|
348
|
+
name: EventName.IDENTITY_PROVIDER_LINKED,
|
|
349
|
+
refType: EventRefType.IDENTITY_PROVIDER_ACCOUNT,
|
|
350
|
+
refId: account.id,
|
|
351
|
+
realmId: account.userRealmId ?? provider.realmId ?? null,
|
|
352
|
+
actorType: IdentityType.USER,
|
|
353
|
+
actorId: account.userId,
|
|
354
|
+
actorName: identity.data.name ?? null,
|
|
355
|
+
sessionId: requestContext?.sessionId ?? null,
|
|
356
|
+
requestPath: requestContext?.requestPath ?? null,
|
|
357
|
+
requestMethod: requestContext?.requestMethod ?? null,
|
|
358
|
+
requestIpAddress: requestContext?.requestIpAddress ?? getRequestIP(event) ?? null,
|
|
359
|
+
requestUserAgent: requestContext?.requestUserAgent ?? getRequestHeader(event, "user-agent") ?? null,
|
|
360
|
+
data: {
|
|
361
|
+
providerId: provider.id,
|
|
362
|
+
providerName: provider.name
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
return {
|
|
366
|
+
data: account,
|
|
367
|
+
meta: {}
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
pickIdentityCandidate(identity, key) {
|
|
371
|
+
const candidates = identity.attributeCandidates?.[key] || [];
|
|
372
|
+
for (const candidate of candidates) if (typeof candidate === "string" && candidate.length > 0) return candidate;
|
|
373
|
+
return null;
|
|
374
|
+
}
|
|
340
375
|
buildHostedAuthorizeURL(codeRequest) {
|
|
341
376
|
const url = new URL(resolveURL(this.options.baseURL, "authorize"));
|
|
342
377
|
const codeRequestKeys = Object.keys(codeRequest);
|
|
@@ -356,6 +391,7 @@ var IdentityProviderController = class {
|
|
|
356
391
|
return createIdentityProviderOAuth2Authenticator({
|
|
357
392
|
accountManager: this.accountManager,
|
|
358
393
|
provider,
|
|
394
|
+
logger: this.logger,
|
|
359
395
|
options: {
|
|
360
396
|
baseURL: this.options.baseURL,
|
|
361
397
|
clientId: options.clientId
|
|
@@ -459,6 +495,19 @@ _ts_decorate([
|
|
|
459
495
|
_ts_metadata("design:paramtypes", [String, typeof IAppEvent === "undefined" ? Object : IAppEvent]),
|
|
460
496
|
_ts_metadata("design:returntype", Promise)
|
|
461
497
|
], IdentityProviderController.prototype, "authorizeIn", null);
|
|
498
|
+
_ts_decorate([
|
|
499
|
+
DPost("/:id/link-confirm", [ForceLoggedInMiddleware]),
|
|
500
|
+
_ts_param(0, DPath("id")),
|
|
501
|
+
_ts_param(1, DBody()),
|
|
502
|
+
_ts_param(2, DContext()),
|
|
503
|
+
_ts_metadata("design:type", Function),
|
|
504
|
+
_ts_metadata("design:paramtypes", [
|
|
505
|
+
String,
|
|
506
|
+
typeof IdentityProviderLinkConfirmPayload === "undefined" ? Object : IdentityProviderLinkConfirmPayload,
|
|
507
|
+
typeof IAppEvent === "undefined" ? Object : IAppEvent
|
|
508
|
+
]),
|
|
509
|
+
_ts_metadata("design:returntype", Promise)
|
|
510
|
+
], IdentityProviderController.prototype, "confirmLink", null);
|
|
462
511
|
IdentityProviderController = _ts_decorate([
|
|
463
512
|
DTags("identity"),
|
|
464
513
|
DController(["/identity-providers", "/realms/:realmId/identity-providers"]),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.mjs","names":["BuiltInPolicyType","definePolicyData","ValidatorGroup","base64URLDecode","isUUID","DBody","DContext","DController","DDelete","DGet","DPath","DPost","DPut","DTags","getRequestHeader","getRequestIP","sendRedirect","EventName","EventRefType","EventScope","IdentityProviderAttributesValidator","IdentityProviderValidator","IdentityType","PermissionName","SessionAuthMethod","isOAuth2IdentityProvider","isOpenIDIdentityProvider","BadRequestError","EntityNotFoundError","describeError","resolveURL","useRequestQuery","readRequestBody","OAuth2ErrorCode","OAuth2RequestError","URL","OAuth2AuthorizationCodeRequestValidator","RECORD_QUERY_PARAMETERS","createIdentityProviderOAuth2Authenticator","decodeQuery","describeQuerySchema","identityProviderSchema","isIdentityProviderAccountAlreadyLinkedError","toIdentityPolicyData","applyRouteRealmIDToBody","buildActorContext","getBodyRealmID","getRequestParamID","getRequestRealmID","useRequestIdentityOrFail","useRequestParamID","useRequestPermissionEvaluator","ForceLoggedInMiddleware","IdentityProviderController","options","repository","realmRepository","clientRepository","accountManager","codeRequestVerifier","codeRequestValidator","stateManager","codeIssuer","accessPolicyEvaluator","eventService","logger","ctx","getProviders","event","data","meta","findMany","schema","actor","permissionEvaluator","preEvaluate","name","IDENTITY_PROVIDER_READ","datum","evaluate","ATTRIBUTES","REALM_MATCH","realmId","getProvider","id","paramId","entity","findOneByIdOrName","editProvider","user","write","updateOnly","put","dropProvider","IDENTITY_PROVIDER_DELETE","findOneBy","entityId","remove","response","status","addProvider","authorizeOut","_id","resolve","authenticator","buildProviderAuthenticator","codeRequest","query","codeRequestDecoded","JSON","parse","malformed","codeRequestValidated","run","verify","client","state","saveAuthorizationState","buildRedirectURL","linkRequest","enabled","identity","type","USER","link","userId","providerId","url","authorizeIn","Error","protocol","verifyAuthorizationState","completeLink","realm_id","code","length","clientId","client_id","authenticate","realm","accessPolicyId","allowed","subject","buildHostedAuthorizeURL","searchParams","set","ACCESS_DENIED","href","authorizationCode","issue","response_type","redirect_uri","scope","authMethod","EXTERNAL","baseURL","group","body","where","IDENTITY_PROVIDER_UPDATE","UPDATE","IDENTITY_PROVIDER_CREATE","CREATE","validator","attributesValidator","attributes","validateJoinColumns","checkUniqueness","undefined","merge","saveWithEA","create","provider","ip","userAgent","resolveIdentity","account","record","IDENTITY","IDENTITY_PROVIDER_LINKED","refType","IDENTITY_PROVIDER_ACCOUNT","refId","userRealmId","actorType","actorId","requestIpAddress","requestUserAgent","providerName","e","error","codeRequestKeys","Object","keys","codeRequestKey_","codeRequestKey","codeRequestValue","String","findOneById","save","stateInvalid"],"sources":["../../../../../../src/adapters/http/controllers/entities/identity-provider/module.ts"],"sourcesContent":["/*\n * Copyright (c) 2022.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { BuiltInPolicyType, definePolicyData } from '@authup/access';\nimport { ValidatorGroup, base64URLDecode, isUUID } from '@authup/kit';\nimport {\n DBody,\n DContext,\n DController,\n DDelete,\n DGet,\n DPath,\n DPost,\n DPut,\n DTags,\n} from '@routup/decorators';\nimport type { IAppEvent } from 'routup';\nimport {\n getRequestHeader,\n getRequestIP,\n sendRedirect,\n} from 'routup';\nimport type {\n IdentityProvider,\n OAuth2AuthorizationCodeRequest,\n OAuth2IdentityProvider,\n OpenIDIdentityProvider,\n} from '@authup/core-kit';\nimport {\n EventName,\n EventRefType,\n EventScope,\n IdentityProviderAttributesValidator,\n IdentityProviderValidator,\n IdentityType,\n PermissionName,\n SessionAuthMethod,\n isOAuth2IdentityProvider,\n isOpenIDIdentityProvider,\n} from '@authup/core-kit';\nimport { BadRequestError, EntityNotFoundError } from '@authup/errors';\nimport type { Logger } from '@authup/server-kit';\nimport { describeError, resolveURL } from '../../../../../utils/index.ts';\nimport { useRequestQuery } from '@routup/basic/query';\nimport { readRequestBody } from '@routup/basic/body';\nimport { OAuth2ErrorCode, OAuth2RequestError } from '@authup/specs';\nimport type {\n EntityCollectionResponse,\n EntityRecordResponse,\n IdentityProviderCreatePayload,\n IdentityProviderLinkRequestResponse,\n IdentityProviderSavePayload,\n IdentityProviderUpdatePayload,\n} from '@authup/core-http-kit';\nimport { URL } from 'node:url';\nimport type {\n IEventService,\n IIdentityProviderAccountManager,\n IIdentityProviderRepository,\n IOAuth2AccessPolicyEvaluator,\n IOAuth2AuthorizationCodeIssuer,\n IOAuth2AuthorizationCodeRequestVerifier,\n IOAuth2AuthorizationStateManager,\n IOAuth2ClientRepository,\n IRealmRepository,\n OAuth2AuthorizationState,\n OAuth2AuthorizationStateLink,\n} from '../../../../../core/index.ts';\nimport {\n OAuth2AuthorizationCodeRequestValidator,\n RECORD_QUERY_PARAMETERS,\n createIdentityProviderOAuth2Authenticator,\n decodeQuery,\n describeQuerySchema,\n identityProviderSchema,\n isIdentityProviderAccountAlreadyLinkedError,\n toIdentityPolicyData,\n} from '../../../../../core/index.ts';\nimport {\n applyRouteRealmIDToBody,\n buildActorContext,\n getBodyRealmID,\n getRequestParamID,\n getRequestRealmID,\n useRequestIdentityOrFail,\n useRequestParamID,\n useRequestPermissionEvaluator,\n} from '../../../request/index.ts';\nimport { ForceLoggedInMiddleware } from '../../../middleware/index.ts';\nimport type { IdentityProviderControllerContext, IdentityProviderControllerOptions } from './types.ts';\n\n@DTags('identity')\n@DController(['/identity-providers', '/realms/:realmId/identity-providers'])\nexport class IdentityProviderController {\n protected options: IdentityProviderControllerOptions;\n\n protected repository: IIdentityProviderRepository;\n\n protected realmRepository: IRealmRepository;\n\n protected clientRepository: IOAuth2ClientRepository;\n\n protected accountManager: IIdentityProviderAccountManager;\n\n protected codeRequestVerifier : IOAuth2AuthorizationCodeRequestVerifier;\n\n protected codeRequestValidator : OAuth2AuthorizationCodeRequestValidator;\n\n protected stateManager : IOAuth2AuthorizationStateManager;\n\n protected codeIssuer : IOAuth2AuthorizationCodeIssuer;\n\n protected accessPolicyEvaluator? : IOAuth2AccessPolicyEvaluator;\n\n protected eventService? : IEventService;\n\n protected logger? : Logger;\n\n // ---------------------------------------------------------\n\n constructor(ctx: IdentityProviderControllerContext) {\n this.options = ctx.options;\n this.repository = ctx.repository;\n this.realmRepository = ctx.realmRepository;\n this.clientRepository = ctx.clientRepository;\n this.accountManager = ctx.accountManager;\n this.codeIssuer = ctx.codeIssuer;\n this.codeRequestVerifier = ctx.codeRequestVerifier;\n this.codeRequestValidator = new OAuth2AuthorizationCodeRequestValidator();\n this.stateManager = ctx.stateManager;\n this.accessPolicyEvaluator = ctx.accessPolicyEvaluator;\n this.eventService = ctx.eventService;\n this.logger = ctx.logger;\n }\n\n // ---------------------------------------------------------\n\n @DGet('', [])\n async getProviders(\n @DContext() event: IAppEvent,\n ): Promise<EntityCollectionResponse<IdentityProvider>> {\n const {\n data,\n meta,\n } = await this.repository.findMany(\n await decodeQuery(useRequestQuery(event), {\n schema: identityProviderSchema,\n actor: buildActorContext(event),\n }),\n );\n\n try {\n const permissionEvaluator = useRequestPermissionEvaluator(event);\n await permissionEvaluator.preEvaluate({ name: PermissionName.IDENTITY_PROVIDER_READ });\n\n for (const datum of data) {\n try {\n await permissionEvaluator.evaluate({\n name: PermissionName.IDENTITY_PROVIDER_READ,\n data: definePolicyData({ [BuiltInPolicyType.ATTRIBUTES]: datum, [BuiltInPolicyType.REALM_MATCH]: datum.realmId ?? null }),\n });\n } catch {\n // do nothing\n }\n }\n } catch {\n // do nothing\n }\n\n return {\n data,\n meta: {\n ...meta,\n schema: describeQuerySchema(identityProviderSchema),\n },\n };\n }\n\n @DGet('/:id', [])\n async getProvider(\n @DPath('id') id: string,\n @DContext() event: IAppEvent,\n ): Promise<EntityRecordResponse<IdentityProvider>> {\n const paramId = useRequestParamID(event, { isUUID: false });\n\n const entity = await this.repository.findOneByIdOrName(\n paramId,\n getRequestRealmID(event),\n );\n\n if (!entity) {\n throw new EntityNotFoundError();\n }\n\n try {\n const permissionEvaluator = useRequestPermissionEvaluator(event);\n await permissionEvaluator.evaluate({\n name: PermissionName.IDENTITY_PROVIDER_READ,\n data: definePolicyData({ [BuiltInPolicyType.ATTRIBUTES]: entity, [BuiltInPolicyType.REALM_MATCH]: entity.realmId ?? null }),\n });\n } catch {\n // do nothing\n }\n\n return { data: entity, meta: { schema: describeQuerySchema(identityProviderSchema, RECORD_QUERY_PARAMETERS) } };\n }\n\n @DPost('/:id', [ForceLoggedInMiddleware])\n async editProvider(\n @DPath('id') id: string,\n @DBody() user: IdentityProviderUpdatePayload,\n @DContext() event: IAppEvent,\n ) : Promise<EntityRecordResponse<IdentityProvider>> {\n return this.write(event, { updateOnly: true });\n }\n\n @DPut('/:id', [ForceLoggedInMiddleware])\n async put(\n @DPath('id') id: string,\n @DBody() user: IdentityProviderSavePayload,\n @DContext() event: IAppEvent,\n ) : Promise<EntityRecordResponse<IdentityProvider>> {\n return this.write(event);\n }\n\n @DDelete('/:id', [ForceLoggedInMiddleware])\n async dropProvider(\n @DPath('id') id: string,\n @DContext() event: IAppEvent,\n ) : Promise<EntityRecordResponse<IdentityProvider>> {\n const paramId = useRequestParamID(event);\n\n const permissionEvaluator = useRequestPermissionEvaluator(event);\n await permissionEvaluator.preEvaluate({ name: PermissionName.IDENTITY_PROVIDER_DELETE });\n\n const entity = await this.repository.findOneBy({ id: paramId });\n\n if (!entity) {\n throw new EntityNotFoundError();\n }\n\n await permissionEvaluator.evaluate({\n name: PermissionName.IDENTITY_PROVIDER_DELETE,\n data: definePolicyData({ [BuiltInPolicyType.ATTRIBUTES]: entity, [BuiltInPolicyType.REALM_MATCH]: entity.realmId ?? null }),\n });\n\n const { id: entityId } = entity;\n\n await this.repository.remove(entity);\n\n entity.id = entityId;\n\n event.response.status = 202;\n\n return { data: entity, meta: {} };\n }\n\n @DPost('', [ForceLoggedInMiddleware])\n async addProvider(\n @DBody() user: IdentityProviderCreatePayload,\n @DContext() event: IAppEvent,\n ) : Promise<EntityRecordResponse<IdentityProvider>> {\n return this.write(event);\n }\n\n // ---------------------------------------------------------\n\n @DGet('/:id/authorize-out', [])\n async authorizeOut(\n @DPath('id') _id: string,\n @DContext() event: IAppEvent,\n ) {\n const id = useRequestParamID(event);\n const entity = await this.resolve(id);\n\n if (!isOAuth2IdentityProvider(entity) && !isOpenIDIdentityProvider(entity)) {\n throw new BadRequestError('Only an identity-provider based on the oauth protocol supports authorize redirect.');\n }\n\n const authenticator = this.buildProviderAuthenticator(entity);\n\n let codeRequest: OAuth2AuthorizationCodeRequest | undefined;\n const query = useRequestQuery(event);\n if (typeof query.codeRequest === 'string') {\n let codeRequestDecoded: OAuth2AuthorizationCodeRequest;\n\n try {\n codeRequestDecoded = JSON.parse(base64URLDecode(query.codeRequest));\n } catch {\n throw OAuth2RequestError.malformed('The code request is malformed and can not be parsed.');\n }\n\n const codeRequestValidated = await this.codeRequestValidator.run(codeRequestDecoded);\n const data = await this.codeRequestVerifier.verify(codeRequestValidated);\n\n if (\n data.client.realmId &&\n entity.realmId &&\n entity.realmId !== data.client.realmId\n ) {\n throw OAuth2RequestError.malformed('The provider and client realm do not match.');\n }\n\n codeRequest = data.data;\n }\n\n const state = await this.saveAuthorizationState(event, { codeRequest });\n\n return sendRedirect(event, authenticator.buildRedirectURL({ state }));\n }\n\n @DPost('/:id/link-request', [ForceLoggedInMiddleware])\n async linkRequest(\n @DPath('id') _id: string,\n @DContext() event: IAppEvent,\n ) : Promise<IdentityProviderLinkRequestResponse> {\n const id = useRequestParamID(event);\n const entity = await this.resolve(id);\n\n if (!isOAuth2IdentityProvider(entity) && !isOpenIDIdentityProvider(entity)) {\n throw new BadRequestError('Only an identity-provider based on the oauth protocol supports account linking.');\n }\n\n if (!entity.enabled) {\n throw new BadRequestError('The identity provider is not enabled.');\n }\n\n const identity = useRequestIdentityOrFail(event);\n if (identity.type !== IdentityType.USER) {\n throw new BadRequestError('Only a user can link an identity provider account.');\n }\n\n if (entity.realmId && entity.realmId !== identity.realmId) {\n throw new BadRequestError('The identity provider does not belong to the user realm.');\n }\n\n const authenticator = this.buildProviderAuthenticator(entity);\n\n const state = await this.saveAuthorizationState(event, { link: { userId: identity.id, providerId: entity.id } });\n\n return { url: authenticator.buildRedirectURL({ state }) };\n }\n\n @DGet('/:id/authorize-in', [])\n async authorizeIn(\n @DPath('id') _id: string,\n @DContext() event: IAppEvent,\n ) {\n const id = useRequestParamID(event);\n\n const entity = await this.resolve(id);\n\n if (!isOAuth2IdentityProvider(entity) && !isOpenIDIdentityProvider(entity)) {\n throw new Error(`The provider protocol ${entity.protocol} is not valid.`);\n }\n\n const data = await this.verifyAuthorizationState(event);\n\n const { link } = data;\n if (link) {\n return this.completeLink(event, entity, data, link);\n }\n\n if (\n entity.realmId &&\n data.codeRequest &&\n data.codeRequest.realm_id &&\n data.codeRequest.realm_id !== entity.realmId\n ) {\n throw OAuth2RequestError.malformed('The provider and client realm do not match.');\n }\n\n const { code } = useRequestQuery(event);\n\n if (typeof code !== 'string' || code.length === 0) {\n throw new BadRequestError('The authorization code is missing.');\n }\n\n const authenticator = this.buildProviderAuthenticator(entity, { clientId: data.codeRequest?.client_id });\n\n const user = await authenticator.authenticate({ code });\n\n const realm = await this.realmRepository.resolve(entity.realmId, true);\n\n // Application access policy (plan 052), federated leg: the callback\n // never redirects to the RP directly — a denial bounces back to the\n // hosted authorize page with error=access_denied, so no\n // redirectUriVerified threading through the state blob is needed.\n // A policy id with no wired evaluator denies (fail closed); a\n // since-deleted client is skipped (the /token backstop still covers it).\n if (data.codeRequest?.client_id) {\n const client = await this.clientRepository.findOneByIdOrName(\n data.codeRequest.client_id,\n data.codeRequest.realm_id,\n );\n\n if (client?.accessPolicyId) {\n let allowed = false;\n\n const subject = toIdentityPolicyData({\n type: IdentityType.USER,\n data: {\n ...user,\n realm,\n },\n });\n if (this.accessPolicyEvaluator && subject) {\n allowed = await this.accessPolicyEvaluator.evaluate(\n client.accessPolicyId,\n subject,\n );\n }\n\n if (!allowed) {\n const url = this.buildHostedAuthorizeURL(data.codeRequest);\n url.searchParams.set('error', OAuth2ErrorCode.ACCESS_DENIED);\n\n return sendRedirect(event, url.href);\n }\n }\n }\n\n const authorizationCode = await this.codeIssuer.issue(\n {\n response_type: 'code',\n client_id: data.codeRequest?.client_id,\n redirect_uri: data.codeRequest?.redirect_uri,\n scope: data.codeRequest?.scope,\n },\n {\n type: IdentityType.USER,\n data: {\n ...user,\n realm,\n },\n },\n { authMethod: SessionAuthMethod.EXTERNAL },\n );\n\n if (data.codeRequest) {\n const url = this.buildHostedAuthorizeURL(data.codeRequest);\n url.searchParams.set('code', authorizationCode.id);\n\n return sendRedirect(event, url.href);\n }\n\n const url = new URL(this.options.baseURL);\n url.searchParams.set('code', authorizationCode.id);\n\n return sendRedirect(event, url.href);\n }\n\n // ---------------------------------------------------------\n\n private async write(event: IAppEvent, options: {\n updateOnly?: boolean\n } = {}): Promise<EntityRecordResponse<IdentityProvider>> {\n let group: string;\n const id = getRequestParamID(event, { isUUID: false });\n const body = await readRequestBody(event);\n applyRouteRealmIDToBody(event, body);\n const realmId = getRequestRealmID(event) ?? getBodyRealmID(body);\n\n let entity: IdentityProvider | null | undefined;\n if (id) {\n const where: Record<string, any> = {};\n if (isUUID(id)) {\n where.id = id;\n } else {\n where.name = id;\n }\n\n if (realmId) {\n where.realmId = realmId;\n }\n\n entity = await this.repository.findOneBy(where);\n // Only a NAME key may upsert-create. A UUID addresses one specific\n // row, so a miss is a 404 (creating would write a different id).\n if (!entity && (options.updateOnly || where.id)) {\n throw new EntityNotFoundError();\n }\n } else if (options.updateOnly) {\n throw new EntityNotFoundError();\n }\n\n const permissionEvaluator = useRequestPermissionEvaluator(event);\n if (entity) {\n await permissionEvaluator.preEvaluate({ name: PermissionName.IDENTITY_PROVIDER_UPDATE });\n\n group = ValidatorGroup.UPDATE;\n } else {\n await permissionEvaluator.preEvaluate({ name: PermissionName.IDENTITY_PROVIDER_CREATE });\n\n group = ValidatorGroup.CREATE;\n }\n\n const validator = new IdentityProviderValidator();\n const data = await validator.run(body, { group });\n\n const attributesValidator = new IdentityProviderAttributesValidator();\n const attributes = await attributesValidator.run(body);\n\n await this.repository.validateJoinColumns(data);\n\n if (entity) {\n await permissionEvaluator.evaluate({\n name: PermissionName.IDENTITY_PROVIDER_UPDATE,\n data: definePolicyData({\n [BuiltInPolicyType.ATTRIBUTES]: {\n ...entity,\n ...data,\n },\n [BuiltInPolicyType.REALM_MATCH]: data.realmId ?? entity.realmId ?? null,\n }),\n });\n } else {\n if (!data.realmId) {\n const identity = useRequestIdentityOrFail(event);\n data.realmId = identity.realmId;\n }\n\n await permissionEvaluator.evaluate({\n name: PermissionName.IDENTITY_PROVIDER_CREATE,\n data: definePolicyData({ [BuiltInPolicyType.ATTRIBUTES]: data, [BuiltInPolicyType.REALM_MATCH]: data.realmId ?? null }),\n });\n }\n\n await this.repository.checkUniqueness(data, entity || undefined);\n\n if (entity) {\n entity = this.repository.merge(entity, data);\n await this.repository.saveWithEA(entity, attributes);\n\n event.response.status = 202;\n\n return { data: entity, meta: {} };\n }\n\n entity = this.repository.create(data);\n await this.repository.saveWithEA(entity, attributes);\n\n event.response.status = 201;\n\n return { data: entity, meta: {} };\n }\n\n // ---------------------------------------------------------\n\n /**\n * Callback half of the account-linking round-trip (plan 091): the\n * external identity is bound to the state-referenced user instead of\n * running the login path. No auth code and no session is minted; the\n * browser lands back on the account console with a marker param.\n */\n private async completeLink(\n event: IAppEvent,\n provider: OAuth2IdentityProvider | OpenIDIdentityProvider,\n state: OAuth2AuthorizationState,\n link: OAuth2AuthorizationStateLink,\n ) {\n // Fixed, server-derived return target (the account console page).\n // No client-supplied redirect exists on this path.\n const url = new URL(resolveURL(this.options.baseURL, 'account/connected-accounts'));\n\n const { code } = useRequestQuery(event);\n\n try {\n // The state is bound to the provider it was minted for, and the\n // provider must still be enabled at completion — a state cannot\n // be replayed against a different provider's callback, nor\n // complete a link after its provider was disabled.\n if (link.providerId !== provider.id || !provider.enabled) {\n throw new BadRequestError('The identity provider is not available for account linking.');\n }\n\n // The state must be bound to the browser that minted it. Both\n // bindings come from the minting request itself\n // (`saveAuthorizationState` stores its ip and user-agent) and\n // `OAuth2AuthorizationStateManager.verify` skips a check whose\n // STORED value is falsy, so an absent binding is a choice the\n // minter made rather than a property of the network — and it\n // leaves the state completable in any browser.\n //\n // On the login path that is a session-fixation nuisance. Here it\n // is a durable credential binding: an attacker who mints a state\n // carrying their OWN userId and gets a victim to follow it binds\n // the VICTIM's external identity to the attacker's account, and\n // the victim's next federated login then lands in it. Refuse an\n // unbound state instead of linking on it.\n //\n // This closes the absent-binding hole only. ip + user-agent\n // remain guessable, and with the shipped `trustProxy: true` the\n // ip is the client-supplied left-most X-Forwarded-For entry, so\n // this is a stopgap: see issue #3439 for moving the write behind\n // a bearer-authenticated confirmation.\n if (!state.ip || !state.userAgent) {\n throw new BadRequestError('The account link request is not bound to a browser.');\n }\n\n if (typeof code !== 'string' || code.length === 0) {\n throw new BadRequestError('The authorization code is missing.');\n }\n\n const authenticator = this.buildProviderAuthenticator(provider);\n\n const identity = await authenticator.resolveIdentity({ code });\n const account = await this.accountManager.link(identity, link.userId);\n\n await this.eventService?.record({\n scope: EventScope.IDENTITY,\n name: EventName.IDENTITY_PROVIDER_LINKED,\n refType: EventRefType.IDENTITY_PROVIDER_ACCOUNT,\n refId: account.id,\n realmId: account.userRealmId ?? provider.realmId ?? null,\n actorType: IdentityType.USER,\n actorId: account.userId,\n requestIpAddress: getRequestIP(event) ?? null,\n requestUserAgent: getRequestHeader(event, 'user-agent') ?? null,\n data: { providerId: provider.id, providerName: provider.name },\n });\n\n url.searchParams.set('linked', provider.id);\n } catch (e) {\n // The failure is swallowed into a redirect marker, so the log is\n // the only surface it can reach. Without this an unreachable or\n // rejecting provider is indistinguishable from a stale state.\n this.logger?.error(describeError(e, 'The identity-provider account link failed.'));\n\n url.searchParams.set(\n 'linkError',\n isIdentityProviderAccountAlreadyLinkedError(e) ? 'already_linked' : 'link_failed',\n );\n }\n\n return sendRedirect(event, url.href);\n }\n\n // ---------------------------------------------------------\n\n private buildHostedAuthorizeURL(codeRequest: OAuth2AuthorizationCodeRequest): URL {\n const url = new URL(resolveURL(this.options.baseURL, 'authorize'));\n\n const codeRequestKeys = Object.keys(codeRequest);\n for (const codeRequestKey_ of codeRequestKeys) {\n const codeRequestKey = codeRequestKey_ as keyof OAuth2AuthorizationCodeRequest;\n const codeRequestValue = codeRequest[codeRequestKey];\n // Preserve meaningful falsy values (e.g. max_age=0, which OIDC\n // treats as prompt=login) — only skip absent ones.\n if (typeof codeRequestValue !== 'undefined' && codeRequestValue !== null) {\n url.searchParams.set(codeRequestKey, String(codeRequestValue));\n }\n }\n\n return url;\n }\n\n // ---------------------------------------------------------\n\n private async resolve(id: string) {\n const entity = await this.repository.findOneById(id);\n\n if (!entity) {\n throw new EntityNotFoundError();\n }\n\n return entity;\n }\n\n // ---------------------------------------------------------\n\n private buildProviderAuthenticator(\n provider: OAuth2IdentityProvider | OpenIDIdentityProvider,\n options: { clientId?: string } = {},\n ) {\n return createIdentityProviderOAuth2Authenticator({\n accountManager: this.accountManager,\n provider,\n options: {\n baseURL: this.options.baseURL,\n clientId: options.clientId,\n },\n });\n }\n\n private async saveAuthorizationState(\n event: IAppEvent,\n data: Pick<OAuth2AuthorizationState, 'codeRequest' | 'link'> = {},\n ) : Promise<string> {\n return this.stateManager.save({\n ...data,\n ip: getRequestIP(event) ?? '',\n userAgent: getRequestHeader(event, 'user-agent') ?? undefined,\n });\n }\n\n private async verifyAuthorizationState(event: IAppEvent): Promise<OAuth2AuthorizationState> {\n const query = useRequestQuery(event);\n if (typeof query.state !== 'string') {\n throw OAuth2RequestError.stateInvalid();\n }\n\n return this.stateManager.verify(query.state, {\n ip: getRequestIP(event) ?? '',\n userAgent: getRequestHeader(event, 'user-agent') ?? undefined,\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"module.mjs","names":["BuiltInPolicyType","definePolicyData","ValidatorGroup","base64URLDecode","isObject","isUUID","DBody","DContext","DController","DDelete","DGet","DPath","DPost","DPut","DTags","getRequestHeader","getRequestIP","sendRedirect","EventName","EventRefType","EventScope","IdentityProviderAttributesValidator","IdentityProviderValidator","IdentityType","PermissionName","buildIdentityProviderAuthorizeCallbackPath","isOAuth2IdentityProvider","isOpenIDIdentityProvider","BadRequestError","EntityNotFoundError","describeError","resolveURL","useRequestQuery","readRequestBody","OAuth2RequestError","URL","OAuth2AuthorizationCodeRequestValidator","RECORD_QUERY_PARAMETERS","createIdentityProviderOAuth2Authenticator","decodeQuery","describeQuerySchema","identityProviderSchema","applyRouteRealmIDToBody","buildActorContext","getBodyRealmID","getRequestParamID","getRequestRealmID","useRequestEventContext","useRequestIdentityOrFail","useRequestParamID","useRequestPermissionEvaluator","ForceLoggedInMiddleware","renderAuthConsolePage","IdentityProviderController","options","repository","accountManager","linkStore","codeRequestVerifier","codeRequestValidator","stateManager","loginService","eventService","logger","ctx","getProviders","event","data","meta","findMany","schema","actor","permissionEvaluator","preEvaluate","name","IDENTITY_PROVIDER_READ","datum","evaluate","ATTRIBUTES","REALM_MATCH","realmId","getProvider","id","paramId","entity","findOneByIdOrName","editProvider","user","write","updateOnly","put","dropProvider","IDENTITY_PROVIDER_DELETE","findOneBy","entityId","remove","response","status","addProvider","authorizeOut","_id","resolve","enabled","query","codeRequest","malformed","codeRequestDecoded","JSON","parse","codeRequestValidated","run","verify","client","authenticator","buildProviderAuthenticator","state","saveAuthorizationState","buildRedirectURL","linkRequest","identity","type","USER","link","userId","providerId","url","authorizeIn","Error","protocol","verifyAuthorizationState","completeLink","code","error","length","info","stringify","slice","buildHostedAuthorizeURL","href","result","complete","provider","request","ipAddress","userAgent","kind","searchParams","set","redirectUri","payload","redirect","authorizeUrl","config","baseURL","group","body","where","IDENTITY_PROVIDER_UPDATE","UPDATE","IDENTITY_PROVIDER_CREATE","CREATE","validator","attributesValidator","attributes","validateJoinColumns","checkUniqueness","undefined","merge","saveWithEA","create","resolveIdentity","handle","save","providerUserId","providerUserName","pickIdentityCandidate","providerUserEmail","e","confirmLink","_data","consume","account","attributeCandidates","email","requestContext","record","scope","IDENTITY","IDENTITY_PROVIDER_LINKED","refType","IDENTITY_PROVIDER_ACCOUNT","refId","userRealmId","actorType","actorId","actorName","sessionId","requestPath","requestMethod","requestIpAddress","requestUserAgent","providerName","key","candidates","candidate","codeRequestKeys","Object","keys","codeRequestKey_","codeRequestKey","codeRequestValue","String","findOneById","clientId","ip","stateInvalid"],"sources":["../../../../../../src/adapters/http/controllers/entities/identity-provider/module.ts"],"sourcesContent":["/*\n * Copyright (c) 2022.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { BuiltInPolicyType, definePolicyData } from '@authup/access';\nimport {\n ValidatorGroup,\n base64URLDecode,\n isObject,\n isUUID,\n} from '@authup/kit';\nimport {\n DBody,\n DContext,\n DController,\n DDelete,\n DGet,\n DPath,\n DPost,\n DPut,\n DTags,\n} from '@routup/decorators';\nimport type { IAppEvent } from 'routup';\nimport {\n getRequestHeader,\n getRequestIP,\n sendRedirect,\n} from 'routup';\nimport type {\n IdentityProvider,\n IdentityProviderAccount,\n OAuth2AuthorizationCodeRequest,\n OAuth2IdentityProvider,\n OpenIDIdentityProvider,\n} from '@authup/core-kit';\nimport {\n EventName,\n EventRefType,\n EventScope,\n IdentityProviderAttributesValidator,\n IdentityProviderValidator,\n IdentityType,\n PermissionName,\n buildIdentityProviderAuthorizeCallbackPath,\n isOAuth2IdentityProvider,\n isOpenIDIdentityProvider,\n} from '@authup/core-kit';\nimport { BadRequestError, EntityNotFoundError } from '@authup/errors';\nimport type { Logger } from '@authup/server-kit';\nimport { describeError, resolveURL } from '../../../../../utils/index.ts';\nimport { useRequestQuery } from '@routup/basic/query';\nimport { readRequestBody } from '@routup/basic/body';\nimport { OAuth2RequestError } from '@authup/specs';\nimport type {\n EntityCollectionResponse,\n EntityRecordResponse,\n IdentityProviderCreatePayload,\n IdentityProviderLinkConfirmPayload,\n IdentityProviderLinkRequestResponse,\n IdentityProviderSavePayload,\n IdentityProviderUpdatePayload,\n} from '@authup/core-http-kit';\nimport { URL } from 'node:url';\nimport type {\n IEventService,\n IIdentityProviderAccountLinkStore,\n IIdentityProviderAccountManager,\n IIdentityProviderRepository,\n IOAuth2AuthorizationCodeRequestVerifier,\n IOAuth2AuthorizationStateManager,\n IOAuth2FederatedLoginService,\n IdentityProviderIdentity,\n OAuth2AuthorizationState,\n OAuth2AuthorizationStateLink,\n} from '../../../../../core/index.ts';\nimport {\n OAuth2AuthorizationCodeRequestValidator,\n RECORD_QUERY_PARAMETERS,\n createIdentityProviderOAuth2Authenticator,\n decodeQuery,\n describeQuerySchema,\n identityProviderSchema,\n} from '../../../../../core/index.ts';\nimport {\n applyRouteRealmIDToBody,\n buildActorContext,\n getBodyRealmID,\n getRequestParamID,\n getRequestRealmID,\n useRequestEventContext,\n useRequestIdentityOrFail,\n useRequestParamID,\n useRequestPermissionEvaluator,\n} from '../../../request/index.ts';\nimport { ForceLoggedInMiddleware } from '../../../middleware/index.ts';\nimport type { IdentityProviderCallbackPayload } from '@authup/client-auth-console';\nimport { renderAuthConsolePage } from '../../../ui/index.ts';\nimport type { IdentityProviderControllerContext, IdentityProviderControllerOptions } from './types.ts';\n\n@DTags('identity')\n@DController(['/identity-providers', '/realms/:realmId/identity-providers'])\nexport class IdentityProviderController {\n protected options: IdentityProviderControllerOptions;\n\n protected repository: IIdentityProviderRepository;\n\n protected accountManager: IIdentityProviderAccountManager;\n\n protected linkStore: IIdentityProviderAccountLinkStore;\n\n protected codeRequestVerifier : IOAuth2AuthorizationCodeRequestVerifier;\n\n protected codeRequestValidator : OAuth2AuthorizationCodeRequestValidator;\n\n protected stateManager : IOAuth2AuthorizationStateManager;\n\n protected loginService : IOAuth2FederatedLoginService;\n\n protected eventService? : IEventService;\n\n protected logger? : Logger;\n\n // ---------------------------------------------------------\n\n constructor(ctx: IdentityProviderControllerContext) {\n this.options = ctx.options;\n this.repository = ctx.repository;\n this.accountManager = ctx.accountManager;\n this.linkStore = ctx.linkStore;\n this.codeRequestVerifier = ctx.codeRequestVerifier;\n this.codeRequestValidator = new OAuth2AuthorizationCodeRequestValidator();\n this.stateManager = ctx.stateManager;\n this.loginService = ctx.loginService;\n this.eventService = ctx.eventService;\n this.logger = ctx.logger;\n }\n\n // ---------------------------------------------------------\n\n @DGet('', [])\n async getProviders(\n @DContext() event: IAppEvent,\n ): Promise<EntityCollectionResponse<IdentityProvider>> {\n const {\n data,\n meta,\n } = await this.repository.findMany(\n await decodeQuery(useRequestQuery(event), {\n schema: identityProviderSchema,\n actor: buildActorContext(event),\n }),\n );\n\n try {\n const permissionEvaluator = useRequestPermissionEvaluator(event);\n await permissionEvaluator.preEvaluate({ name: PermissionName.IDENTITY_PROVIDER_READ });\n\n for (const datum of data) {\n try {\n await permissionEvaluator.evaluate({\n name: PermissionName.IDENTITY_PROVIDER_READ,\n data: definePolicyData({ [BuiltInPolicyType.ATTRIBUTES]: datum, [BuiltInPolicyType.REALM_MATCH]: datum.realmId ?? null }),\n });\n } catch {\n // do nothing\n }\n }\n } catch {\n // do nothing\n }\n\n return {\n data,\n meta: {\n ...meta,\n schema: describeQuerySchema(identityProviderSchema),\n },\n };\n }\n\n @DGet('/:id', [])\n async getProvider(\n @DPath('id') id: string,\n @DContext() event: IAppEvent,\n ): Promise<EntityRecordResponse<IdentityProvider>> {\n const paramId = useRequestParamID(event, { isUUID: false });\n\n const entity = await this.repository.findOneByIdOrName(\n paramId,\n getRequestRealmID(event),\n );\n\n if (!entity) {\n throw new EntityNotFoundError();\n }\n\n try {\n const permissionEvaluator = useRequestPermissionEvaluator(event);\n await permissionEvaluator.evaluate({\n name: PermissionName.IDENTITY_PROVIDER_READ,\n data: definePolicyData({ [BuiltInPolicyType.ATTRIBUTES]: entity, [BuiltInPolicyType.REALM_MATCH]: entity.realmId ?? null }),\n });\n } catch {\n // do nothing\n }\n\n return { data: entity, meta: { schema: describeQuerySchema(identityProviderSchema, RECORD_QUERY_PARAMETERS) } };\n }\n\n @DPost('/:id', [ForceLoggedInMiddleware])\n async editProvider(\n @DPath('id') id: string,\n @DBody() user: IdentityProviderUpdatePayload,\n @DContext() event: IAppEvent,\n ) : Promise<EntityRecordResponse<IdentityProvider>> {\n return this.write(event, { updateOnly: true });\n }\n\n @DPut('/:id', [ForceLoggedInMiddleware])\n async put(\n @DPath('id') id: string,\n @DBody() user: IdentityProviderSavePayload,\n @DContext() event: IAppEvent,\n ) : Promise<EntityRecordResponse<IdentityProvider>> {\n return this.write(event);\n }\n\n @DDelete('/:id', [ForceLoggedInMiddleware])\n async dropProvider(\n @DPath('id') id: string,\n @DContext() event: IAppEvent,\n ) : Promise<EntityRecordResponse<IdentityProvider>> {\n const paramId = useRequestParamID(event);\n\n const permissionEvaluator = useRequestPermissionEvaluator(event);\n await permissionEvaluator.preEvaluate({ name: PermissionName.IDENTITY_PROVIDER_DELETE });\n\n const entity = await this.repository.findOneBy({ id: paramId });\n\n if (!entity) {\n throw new EntityNotFoundError();\n }\n\n await permissionEvaluator.evaluate({\n name: PermissionName.IDENTITY_PROVIDER_DELETE,\n data: definePolicyData({ [BuiltInPolicyType.ATTRIBUTES]: entity, [BuiltInPolicyType.REALM_MATCH]: entity.realmId ?? null }),\n });\n\n const { id: entityId } = entity;\n\n await this.repository.remove(entity);\n\n entity.id = entityId;\n\n event.response.status = 202;\n\n return { data: entity, meta: {} };\n }\n\n @DPost('', [ForceLoggedInMiddleware])\n async addProvider(\n @DBody() user: IdentityProviderCreatePayload,\n @DContext() event: IAppEvent,\n ) : Promise<EntityRecordResponse<IdentityProvider>> {\n return this.write(event);\n }\n\n // ---------------------------------------------------------\n\n @DGet('/:id/authorize-out', [])\n async authorizeOut(\n @DPath('id') _id: string,\n @DContext() event: IAppEvent,\n ) {\n const id = useRequestParamID(event);\n const entity = await this.resolve(id);\n\n if (!isOAuth2IdentityProvider(entity) && !isOpenIDIdentityProvider(entity)) {\n throw new BadRequestError('Only an identity-provider based on the oauth protocol supports authorize redirect.');\n }\n\n // Refused here as well as at the callback, so a disabled provider\n // costs no provider round trip.\n if (!entity.enabled) {\n throw new BadRequestError('The identity provider is not enabled.');\n }\n\n // A federated login completes an RP's authorization request: the\n // callback mints a code bound to that request and delivers it to the\n // request's redirect_uri. Without one there is nowhere to deliver a\n // code (the callback used to mint an unbound one and hand it to the\n // server root, issue #3457), so the login must not start.\n const query = useRequestQuery(event);\n if (typeof query.codeRequest !== 'string') {\n throw OAuth2RequestError.malformed('A federated login requires an authorization code request.');\n }\n\n let codeRequestDecoded: OAuth2AuthorizationCodeRequest;\n\n try {\n codeRequestDecoded = JSON.parse(base64URLDecode(query.codeRequest));\n } catch {\n throw OAuth2RequestError.malformed('The code request is malformed and can not be parsed.');\n }\n\n const codeRequestValidated = await this.codeRequestValidator.run(codeRequestDecoded);\n const data = await this.codeRequestVerifier.verify(codeRequestValidated);\n\n if (\n data.client.realmId &&\n entity.realmId &&\n entity.realmId !== data.client.realmId\n ) {\n throw OAuth2RequestError.malformed('The provider and client realm do not match.');\n }\n\n const authenticator = this.buildProviderAuthenticator(entity);\n\n const state = await this.saveAuthorizationState(event, { codeRequest: data.data });\n\n return sendRedirect(event, authenticator.buildRedirectURL({ state }));\n }\n\n @DPost('/:id/link-request', [ForceLoggedInMiddleware])\n async linkRequest(\n @DPath('id') _id: string,\n @DContext() event: IAppEvent,\n ) : Promise<IdentityProviderLinkRequestResponse> {\n const id = useRequestParamID(event);\n const entity = await this.resolve(id);\n\n if (!isOAuth2IdentityProvider(entity) && !isOpenIDIdentityProvider(entity)) {\n throw new BadRequestError('Only an identity-provider based on the oauth protocol supports account linking.');\n }\n\n if (!entity.enabled) {\n throw new BadRequestError('The identity provider is not enabled.');\n }\n\n const identity = useRequestIdentityOrFail(event);\n if (identity.type !== IdentityType.USER) {\n throw new BadRequestError('Only a user can link an identity provider account.');\n }\n\n if (entity.realmId && entity.realmId !== identity.realmId) {\n throw new BadRequestError('The identity provider does not belong to the user realm.');\n }\n\n const authenticator = this.buildProviderAuthenticator(entity);\n\n const state = await this.saveAuthorizationState(event, { link: { userId: identity.id, providerId: entity.id } });\n\n return { url: authenticator.buildRedirectURL({ state }) };\n }\n\n @DGet('/:id/authorize-in', [])\n async authorizeIn(\n @DPath('id') _id: string,\n @DContext() event: IAppEvent,\n ) {\n const id = useRequestParamID(event);\n\n const entity = await this.resolve(id);\n\n if (!isOAuth2IdentityProvider(entity) && !isOpenIDIdentityProvider(entity)) {\n throw new Error(`The provider protocol ${entity.protocol} is not valid.`);\n }\n\n const data = await this.verifyAuthorizationState(event);\n\n const { link } = data;\n if (link) {\n return this.completeLink(event, entity, data, link);\n }\n\n // authorize-out no longer mints a login state without a code request;\n // this refuses the ones minted before that (issue #3457).\n if (!data.codeRequest) {\n throw OAuth2RequestError.malformed('The state carries no authorization code request.');\n }\n\n const { code, error } = useRequestQuery(event);\n\n // RFC 6749 section 4.1.2.1: a provider answers a refused or failed\n // authorization (the person cancelled at the provider, the provider\n // is down) with `error` and no code. A top-level browser navigation\n // like every other refusal here, so it lands on the hosted login\n // again. Nothing of the provider's answer is echoed: whoever controls\n // the provider's redirect shapes those values.\n if (typeof error === 'string' && error.length > 0) {\n // JSON-quoted: a raw query value must not be able to forge a log line\n this.logger?.info(`The identity provider ${entity.id} answered the authorization with ${JSON.stringify(error.slice(0, 64))}.`);\n\n return sendRedirect(event, this.buildHostedAuthorizeURL(data.codeRequest).href);\n }\n\n if (typeof code !== 'string' || code.length === 0) {\n throw new BadRequestError('The authorization code is missing.');\n }\n\n const result = await this.loginService.complete({\n provider: entity,\n codeRequest: data.codeRequest,\n code,\n request: {\n ipAddress: getRequestIP(event),\n userAgent: getRequestHeader(event, 'user-agent'),\n },\n });\n\n // A refusal is a decision the person at the browser has to be told\n // about, and this is a top-level navigation, so it lands on the\n // hosted login rather than in a JSON body (issue #3458). A marker is\n // only attached when the refusal carries one; without it the page\n // re-runs the same verifier over the same request and states the\n // reason itself, so nothing is echoed.\n if (result.kind === 'refused') {\n const url = this.buildHostedAuthorizeURL(result.codeRequest);\n if (result.error) {\n url.searchParams.set('error', result.error);\n }\n\n return sendRedirect(event, url.href);\n }\n\n // RFC 6749 §4.1.2: the code goes back to the client that asked for it.\n // It is bound to that client_id and that redirect_uri, so the RP is the\n // only party able to redeem it. Handing it to any other page strands\n // the login there (issue #3446).\n const url = new URL(result.redirectUri);\n url.searchParams.set('code', result.code);\n if (result.state) {\n url.searchParams.set('state', result.state);\n }\n\n if (url.protocol === 'http:' || url.protocol === 'https:') {\n return sendRedirect(event, url.href);\n }\n\n // routup's sendRedirect allows http(s) only. A native app's\n // custom-scheme redirect_uri (RFC 8252, matched verbatim by\n // isSimpleURLMatch) is navigated client-side from an interstitial\n // page instead; the target is the verified redirect_uri and nothing\n // else (the service refuses a script-capable scheme), so the page\n // never reaches an unverified one (issue #3459).\n const payload : IdentityProviderCallbackPayload = {\n redirect: url.href,\n // The browser stays on the consumed callback URL, so a reload\n // would re-run the callback against a popped state. The page\n // swaps the history entry for this first, so a reload lands on\n // the hosted login instead.\n authorizeUrl: this.buildHostedAuthorizeURL(result.codeRequest).href,\n client: result.client,\n };\n\n return renderAuthConsolePage(event, {\n url: buildIdentityProviderAuthorizeCallbackPath(entity.id),\n payload: {\n config: { baseURL: this.options.baseURL },\n data: payload,\n },\n });\n }\n\n // ---------------------------------------------------------\n\n private async write(event: IAppEvent, options: {\n updateOnly?: boolean\n } = {}): Promise<EntityRecordResponse<IdentityProvider>> {\n let group: string;\n const id = getRequestParamID(event, { isUUID: false });\n const body = await readRequestBody(event);\n applyRouteRealmIDToBody(event, body);\n const realmId = getRequestRealmID(event) ?? getBodyRealmID(body);\n\n let entity: IdentityProvider | null | undefined;\n if (id) {\n const where: Record<string, any> = {};\n if (isUUID(id)) {\n where.id = id;\n } else {\n where.name = id;\n }\n\n if (realmId) {\n where.realmId = realmId;\n }\n\n entity = await this.repository.findOneBy(where);\n // Only a NAME key may upsert-create. A UUID addresses one specific\n // row, so a miss is a 404 (creating would write a different id).\n if (!entity && (options.updateOnly || where.id)) {\n throw new EntityNotFoundError();\n }\n } else if (options.updateOnly) {\n throw new EntityNotFoundError();\n }\n\n const permissionEvaluator = useRequestPermissionEvaluator(event);\n if (entity) {\n await permissionEvaluator.preEvaluate({ name: PermissionName.IDENTITY_PROVIDER_UPDATE });\n\n group = ValidatorGroup.UPDATE;\n } else {\n await permissionEvaluator.preEvaluate({ name: PermissionName.IDENTITY_PROVIDER_CREATE });\n\n group = ValidatorGroup.CREATE;\n }\n\n const validator = new IdentityProviderValidator();\n const data = await validator.run(body, { group });\n\n const attributesValidator = new IdentityProviderAttributesValidator();\n const attributes = await attributesValidator.run(body);\n\n await this.repository.validateJoinColumns(data);\n\n if (entity) {\n await permissionEvaluator.evaluate({\n name: PermissionName.IDENTITY_PROVIDER_UPDATE,\n data: definePolicyData({\n [BuiltInPolicyType.ATTRIBUTES]: {\n ...entity,\n ...data,\n },\n [BuiltInPolicyType.REALM_MATCH]: data.realmId ?? entity.realmId ?? null,\n }),\n });\n } else {\n if (!data.realmId) {\n const identity = useRequestIdentityOrFail(event);\n data.realmId = identity.realmId;\n }\n\n await permissionEvaluator.evaluate({\n name: PermissionName.IDENTITY_PROVIDER_CREATE,\n data: definePolicyData({ [BuiltInPolicyType.ATTRIBUTES]: data, [BuiltInPolicyType.REALM_MATCH]: data.realmId ?? null }),\n });\n }\n\n await this.repository.checkUniqueness(data, entity || undefined);\n\n if (entity) {\n entity = this.repository.merge(entity, data);\n await this.repository.saveWithEA(entity, attributes);\n\n event.response.status = 202;\n\n return { data: entity, meta: {} };\n }\n\n entity = this.repository.create(data);\n await this.repository.saveWithEA(entity, attributes);\n\n event.response.status = 201;\n\n return { data: entity, meta: {} };\n }\n\n // ---------------------------------------------------------\n\n /**\n * Callback half of the account-linking round-trip (plan 091): the\n * external identity is bound to the state-referenced user instead of\n * running the login path. No auth code and no session is minted; the\n * browser lands back on the account console with a marker param.\n */\n private async completeLink(\n event: IAppEvent,\n provider: OAuth2IdentityProvider | OpenIDIdentityProvider,\n state: OAuth2AuthorizationState,\n link: OAuth2AuthorizationStateLink,\n ) {\n // Fixed, server-derived return target (the account console page).\n // No client-supplied redirect exists on this path.\n const url = new URL(resolveURL(this.options.baseURL, 'account/connected-accounts'));\n\n const { code } = useRequestQuery(event);\n\n try {\n // The state is bound to the provider it was minted for, and the\n // provider must still be enabled at completion — a state cannot\n // be replayed against a different provider's callback, nor\n // complete a link after its provider was disabled.\n if (link.providerId !== provider.id || !provider.enabled) {\n throw new BadRequestError('The identity provider is not available for account linking.');\n }\n\n if (typeof code !== 'string' || code.length === 0) {\n throw new BadRequestError('The authorization code is missing.');\n }\n\n const authenticator = this.buildProviderAuthenticator(provider);\n\n const identity = await authenticator.resolveIdentity({ code });\n\n // A provider answering without a subject has nothing to bind. The\n // callback used to reach `link()`, which rejected it; the stash\n // would otherwise carry an empty providerUserId to the confirm.\n if (!identity.id) {\n throw new BadRequestError('The identity provider returned no subject.');\n }\n\n // Nothing is written here. This request is unauthenticated — the\n // browser round-trip cannot carry a bearer — so the only thing\n // distinguishing the browser that started the link from any other\n // would be the state's ip / user-agent binding, and both values\n // are chosen by whoever minted the state. An attacker minting a\n // state carrying their OWN userId and getting a victim to follow\n // it would otherwise bind the VICTIM's external identity to the\n // attacker's account (issue #3439).\n //\n // The resolved identity is stashed under a one-time handle\n // instead, and the account console confirms it with its bearer.\n // The stash keeps the requesting userId so the confirm can\n // require it to equal the AUTHENTICATED user: the handle is a\n // URL parameter, so it reaches browser history and proxy logs,\n // and on its own it must authorize nothing.\n const handle = await this.linkStore.save({\n providerId: provider.id,\n userId: link.userId,\n providerUserId: identity.id,\n providerUserName: this.pickIdentityCandidate(identity, 'name'),\n providerUserEmail: this.pickIdentityCandidate(identity, 'email'),\n });\n\n url.searchParams.set('linkHandle', handle);\n url.searchParams.set('provider', provider.id);\n } catch (e) {\n // The failure is swallowed into a redirect marker, so the log is\n // the only surface it can reach. Without this an unreachable or\n // rejecting provider is indistinguishable from a stale state.\n this.logger?.error(describeError(e, 'The identity-provider account link failed.'));\n\n url.searchParams.set('linkError', 'link_failed');\n }\n\n return sendRedirect(event, url.href);\n }\n\n /**\n * The bearer-authenticated half of the link (issue #3439): the account\n * row is written here, for the AUTHENTICATED user, never in the callback.\n */\n @DPost('/:id/link-confirm', [ForceLoggedInMiddleware])\n async confirmLink(\n @DPath('id') _id: string,\n @DBody() _data: IdentityProviderLinkConfirmPayload,\n @DContext() event: IAppEvent,\n ) : Promise<EntityRecordResponse<IdentityProviderAccount>> {\n const id = useRequestParamID(event);\n const provider = await this.resolve(id);\n\n if (!isOAuth2IdentityProvider(provider) && !isOpenIDIdentityProvider(provider)) {\n throw new BadRequestError('Only an identity-provider based on the oauth protocol supports account linking.');\n }\n\n if (!provider.enabled) {\n throw new BadRequestError('The identity provider is not enabled.');\n }\n\n const identity = useRequestIdentityOrFail(event);\n if (identity.type !== IdentityType.USER) {\n throw new BadRequestError('Only a user can link an identity provider account.');\n }\n\n const body = await readRequestBody(event);\n const handle = isObject(body) ? body.handle : undefined;\n if (typeof handle !== 'string' || handle.length === 0) {\n throw new BadRequestError('The account link handle is missing.');\n }\n\n const link = await this.linkStore.consume(handle);\n if (!link) {\n throw new BadRequestError('The account link request is unknown or expired.');\n }\n\n // The two checks that make the handle inert on its own: it may only\n // be redeemed by the user it was minted for, and only against the\n // provider it was minted for.\n if (link.userId !== identity.id || link.providerId !== provider.id) {\n throw new BadRequestError('The account link request does not belong to the authenticated user.');\n }\n\n const account = await this.accountManager.link(\n {\n id: link.providerUserId,\n // deliberately rebuilt from the stashed scalars: the resolved\n // identity carries the provider secret and the raw external\n // token payload, neither of which belongs in a cache\n attributeCandidates: {\n name: [link.providerUserName],\n email: [link.providerUserEmail],\n },\n data: {},\n provider,\n },\n identity.id,\n );\n\n // the confirm runs under a bearer, so unlike the callback it CAN be\n // attributed to a session and a route (the unlink emit's shape)\n const requestContext = useRequestEventContext();\n\n await this.eventService?.record({\n scope: EventScope.IDENTITY,\n name: EventName.IDENTITY_PROVIDER_LINKED,\n refType: EventRefType.IDENTITY_PROVIDER_ACCOUNT,\n refId: account.id,\n realmId: account.userRealmId ?? provider.realmId ?? null,\n actorType: IdentityType.USER,\n actorId: account.userId,\n actorName: identity.data.name ?? null,\n sessionId: requestContext?.sessionId ?? null,\n requestPath: requestContext?.requestPath ?? null,\n requestMethod: requestContext?.requestMethod ?? null,\n requestIpAddress: requestContext?.requestIpAddress ?? getRequestIP(event) ?? null,\n requestUserAgent: requestContext?.requestUserAgent ?? getRequestHeader(event, 'user-agent') ?? null,\n data: { providerId: provider.id, providerName: provider.name },\n });\n\n return { data: account, meta: {} };\n }\n\n private pickIdentityCandidate(\n identity: IdentityProviderIdentity,\n key: 'name' | 'email',\n ) : string | null {\n const candidates = identity.attributeCandidates?.[key] || [];\n for (const candidate of candidates) {\n if (typeof candidate === 'string' && candidate.length > 0) {\n return candidate;\n }\n }\n\n return null;\n }\n\n // ---------------------------------------------------------\n\n private buildHostedAuthorizeURL(codeRequest: OAuth2AuthorizationCodeRequest): URL {\n const url = new URL(resolveURL(this.options.baseURL, 'authorize'));\n\n const codeRequestKeys = Object.keys(codeRequest);\n for (const codeRequestKey_ of codeRequestKeys) {\n const codeRequestKey = codeRequestKey_ as keyof OAuth2AuthorizationCodeRequest;\n const codeRequestValue = codeRequest[codeRequestKey];\n // Preserve meaningful falsy values (e.g. max_age=0, which OIDC\n // treats as prompt=login) — only skip absent ones.\n if (typeof codeRequestValue !== 'undefined' && codeRequestValue !== null) {\n url.searchParams.set(codeRequestKey, String(codeRequestValue));\n }\n }\n\n return url;\n }\n\n // ---------------------------------------------------------\n\n private async resolve(id: string) {\n const entity = await this.repository.findOneById(id);\n\n if (!entity) {\n throw new EntityNotFoundError();\n }\n\n return entity;\n }\n\n // ---------------------------------------------------------\n\n private buildProviderAuthenticator(\n provider: OAuth2IdentityProvider | OpenIDIdentityProvider,\n options: { clientId?: string } = {},\n ) {\n return createIdentityProviderOAuth2Authenticator({\n accountManager: this.accountManager,\n provider,\n logger: this.logger,\n options: {\n baseURL: this.options.baseURL,\n clientId: options.clientId,\n },\n });\n }\n\n private async saveAuthorizationState(\n event: IAppEvent,\n data: Pick<OAuth2AuthorizationState, 'codeRequest' | 'link'> = {},\n ) : Promise<string> {\n return this.stateManager.save({\n ...data,\n ip: getRequestIP(event) ?? '',\n userAgent: getRequestHeader(event, 'user-agent') ?? undefined,\n });\n }\n\n private async verifyAuthorizationState(event: IAppEvent): Promise<OAuth2AuthorizationState> {\n const query = useRequestQuery(event);\n if (typeof query.state !== 'string') {\n throw OAuth2RequestError.stateInvalid();\n }\n\n return this.stateManager.verify(query.state, {\n ip: getRequestIP(event) ?? '',\n userAgent: getRequestHeader(event, 'user-agent') ?? undefined,\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import type { Logger } from '@authup/server-kit';
|
|
2
|
-
import type { IEventService, IIdentityProviderAccountManager, IIdentityProviderRepository,
|
|
2
|
+
import type { IEventService, IIdentityProviderAccountLinkStore, IIdentityProviderAccountManager, IIdentityProviderRepository, IOAuth2AuthorizationCodeRequestVerifier, IOAuth2AuthorizationStateManager, IOAuth2FederatedLoginService } from '../../../../../core/index.ts';
|
|
3
3
|
export type IdentityProviderControllerOptions = {
|
|
4
4
|
baseURL: string;
|
|
5
5
|
};
|
|
6
6
|
export type IdentityProviderControllerContext = {
|
|
7
7
|
options: IdentityProviderControllerOptions;
|
|
8
8
|
repository: IIdentityProviderRepository;
|
|
9
|
-
realmRepository: IRealmRepository;
|
|
10
|
-
clientRepository: IOAuth2ClientRepository;
|
|
11
9
|
accountManager: IIdentityProviderAccountManager;
|
|
12
|
-
|
|
10
|
+
linkStore: IIdentityProviderAccountLinkStore;
|
|
13
11
|
codeRequestVerifier: IOAuth2AuthorizationCodeRequestVerifier;
|
|
14
12
|
stateManager: IOAuth2AuthorizationStateManager;
|
|
15
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Owns the federated-login completion ladder. The controller only maps
|
|
15
|
+
* its result onto a transport.
|
|
16
|
+
*/
|
|
17
|
+
loginService: IOAuth2FederatedLoginService;
|
|
16
18
|
eventService?: IEventService;
|
|
17
19
|
logger?: Logger;
|
|
18
20
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../../src/adapters/http/controllers/entities/identity-provider/types.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EACR,aAAa,EACb,+BAA+B,EAC/B,2BAA2B,EAC3B,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../../src/adapters/http/controllers/entities/identity-provider/types.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EACR,aAAa,EACb,iCAAiC,EACjC,+BAA+B,EAC/B,2BAA2B,EAC3B,uCAAuC,EACvC,gCAAgC,EAChC,4BAA4B,EAC/B,MAAM,8BAA8B,CAAC;AAEtC,MAAM,MAAM,iCAAiC,GAAG;IAC5C,OAAO,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,iCAAiC,GAAG;IAC5C,OAAO,EAAE,iCAAiC,CAAC;IAE3C,UAAU,EAAE,2BAA2B,CAAC;IAExC,cAAc,EAAE,+BAA+B,CAAC;IAChD,SAAS,EAAE,iCAAiC,CAAC;IAC7C,mBAAmB,EAAE,uCAAuC,CAAC;IAC7D,YAAY,EAAE,gCAAgC,CAAC;IAC/C;;;OAGG;IACH,YAAY,EAAE,4BAA4B,CAAC;IAE3C,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC"}
|
|
@@ -3,12 +3,12 @@ import "node:url";
|
|
|
3
3
|
import.meta.url;
|
|
4
4
|
import { RECORD_QUERY_PARAMETERS, describeQuerySchema } from "../../../../../core/query/describe.mjs";
|
|
5
5
|
import { realmSchema } from "../../../../../core/entities/realm/schema.mjs";
|
|
6
|
+
import { resolveURL } from "../../../../../utils/url.mjs";
|
|
7
|
+
import "../../../../../utils/index.mjs";
|
|
6
8
|
import "../../../../../core/index.mjs";
|
|
7
9
|
import { buildActorContext } from "../../../request/helpers/actor.mjs";
|
|
8
10
|
import "../../../request/index.mjs";
|
|
9
11
|
import { ForceLoggedInMiddleware } from "../../../middleware/built-in/loggedin/module.mjs";
|
|
10
|
-
import { resolveURL } from "../../../../../utils/url.mjs";
|
|
11
|
-
import "../../../../../utils/index.mjs";
|
|
12
12
|
import "../../../middleware/index.mjs";
|
|
13
13
|
import { getJwkRouteHandler, getJwksRouteHandler } from "../../workflows/jwks/handlers/read.mjs";
|
|
14
14
|
import "../../workflows/index.mjs";
|
|
@@ -3,13 +3,13 @@ import "node:url";
|
|
|
3
3
|
import.meta.url;
|
|
4
4
|
import { RECORD_QUERY_PARAMETERS, describeQuerySchema } from "../../../../../core/query/describe.mjs";
|
|
5
5
|
import { sessionSchema } from "../../../../../core/entities/session/schema.mjs";
|
|
6
|
+
import { isSelfToken } from "../../../../../utils/self-id.mjs";
|
|
7
|
+
import "../../../../../utils/index.mjs";
|
|
6
8
|
import "../../../../../core/index.mjs";
|
|
7
9
|
import { buildActorContext } from "../../../request/helpers/actor.mjs";
|
|
8
10
|
import { useRequestSessionId } from "../../../request/helpers/session-id.mjs";
|
|
9
11
|
import "../../../request/index.mjs";
|
|
10
12
|
import { ForceLoggedInMiddleware } from "../../../middleware/built-in/loggedin/module.mjs";
|
|
11
|
-
import { isSelfToken } from "../../../../../utils/self-id.mjs";
|
|
12
|
-
import "../../../../../utils/index.mjs";
|
|
13
13
|
import "../../../middleware/index.mjs";
|
|
14
14
|
import { useRequestQuery } from "@routup/basic/query";
|
|
15
15
|
import { DContext, DController, DDelete, DGet, DPath, DTags } from "@routup/decorators";
|
|
@@ -3,13 +3,13 @@ import "node:url";
|
|
|
3
3
|
import.meta.url;
|
|
4
4
|
import { RECORD_QUERY_PARAMETERS, describeQuerySchema } from "../../../../../core/query/describe.mjs";
|
|
5
5
|
import { userSchema } from "../../../../../core/entities/user/schema.mjs";
|
|
6
|
+
import { isSelfToken } from "../../../../../utils/self-id.mjs";
|
|
7
|
+
import "../../../../../utils/index.mjs";
|
|
6
8
|
import "../../../../../core/index.mjs";
|
|
7
9
|
import { buildActorContext } from "../../../request/helpers/actor.mjs";
|
|
8
10
|
import { applyRouteRealmIDToBody, getRequestRealmID } from "../../../request/helpers/realm-id.mjs";
|
|
9
11
|
import "../../../request/index.mjs";
|
|
10
12
|
import { ForceLoggedInMiddleware } from "../../../middleware/built-in/loggedin/module.mjs";
|
|
11
|
-
import { isSelfToken } from "../../../../../utils/self-id.mjs";
|
|
12
|
-
import "../../../../../utils/index.mjs";
|
|
13
13
|
import "../../../middleware/index.mjs";
|
|
14
14
|
import { useRequestQuery } from "@routup/basic/query";
|
|
15
15
|
import { DBody, DContext, DController, DDelete, DGet, DPath, DPost, DPut, DTags } from "@routup/decorators";
|