-
Notifications
You must be signed in to change notification settings - Fork 12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add dex auth #2793
feat: add dex auth #2793
Changes from 3 commits
9f7faac
a0381e4
771402b
92d6829
5ca90b9
809f5ae
5c134ed
1aae2e6
c4a37c9
1be464e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -160,6 +160,25 @@ api *command: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
--unstable-fs \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
src/main.ts {{ command }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
debug: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
deno repl \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-A \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
--unstable-fs \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
--eval 'import { getKernel } from "./src/debug.ts"; const kernel = await getKernel();' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
watch: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
deno run \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
--allow-net \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
--allow-env \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
--allow-read \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
--allow-write \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
--allow-ffi \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
--allow-sys \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
--allow-run \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
--watch \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
--unstable-fs \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
src/main.ts http \$PORT | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+169
to
+181
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add PORT validation and review unstable-fs usage. The
Consider adding PORT validation before starting the server: watch:
+ #!/usr/bin/env bash
+ if [[ -z "${PORT}" ]]; then
+ echo "Error: PORT environment variable is not set"
+ exit 1
+ fi
deno run \
--allow-net \
--allow-env \
--allow-read \
--allow-write \
--allow-ffi \
--allow-sys \
--allow-run \
--watch \
--unstable-fs \
src/main.ts http \$PORT 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
# Start the HTTP API server on port 8080 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@serve: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
just api http \$PORT | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
ALTER TABLE auth.users | ||
ALTER COLUMN firstname DROP NOT NULL, | ||
ALTER COLUMN lastname DROP NOT NULL; | ||
|
||
ALTER TABLE territory.territories | ||
ADD COLUMN siret VARCHAR; |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -12,16 +12,21 @@ import { | |||||||||||||||||||||||||||||||||||||||||||||||||||||
Response, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
} from "@/deps.ts"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
children, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
ConfigInterface, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
ConfigInterfaceResolver, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
ContextType, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
InvalidRequestException, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
KernelInterface, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
proxy, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
RegisterHookInterface, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
router, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
RPCResponseType, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
RPCSingleCallType, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
TransportInterface, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
UnauthorizedException, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
} from "@/ilos/common/index.ts"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { ServiceProvider } from "@/ilos/core/index.ts"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { env_or_fail, env_or_false } from "@/lib/env/index.ts"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { logger } from "@/lib/logger/index.ts"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { get } from "@/lib/object/index.ts"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -105,6 +110,7 @@ export class HttpTransport implements TransportInterface { | |||||||||||||||||||||||||||||||||||||||||||||||||||||
this.registerMetrics(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
this.registerGlobalMiddlewares(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
this.registerCache(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
this.registerNestedRoutes(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
this.registerAuthRoutes(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
this.registerApplicationRoutes(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
this.registerCertificateRoutes(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -126,6 +132,18 @@ export class HttpTransport implements TransportInterface { | |||||||||||||||||||||||||||||||||||||||||||||||||||||
return this.app; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
private registerNestedRoutes() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
this.kernel.getContainer().bind(proxy).toConstantValue(this.app); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
const serviceProviders = this.kernel.getContainer().getAll<ServiceProvider>(children); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
for (const serviceProvider of serviceProviders) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
const container = serviceProvider.getContainer(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (container.isBound(router)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
const routerInstance = container.resolve<RegisterHookInterface>(container.get(router)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
routerInstance.register(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+135
to
+145
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add error handling for route registration. The Apply this diff to add error handling: private registerNestedRoutes() {
this.kernel.getContainer().bind(proxy).toConstantValue(this.app);
const serviceProviders = this.kernel.getContainer().getAll<ServiceProvider>(children);
for (const serviceProvider of serviceProviders) {
const container = serviceProvider.getContainer();
if (container.isBound(router)) {
- const routerInstance = container.resolve<RegisterHookInterface>(container.get(router));
- routerInstance.register();
+ try {
+ const routerInstance = container.resolve<RegisterHookInterface>(container.get(router));
+ routerInstance.register();
+ } catch (error) {
+ logger.error(`Failed to register routes for service provider: ${error.message}`);
+ }
}
}
} 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
private async getProviders(): Promise<void> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
this.config = this.kernel.getContainer().get(ConfigInterfaceResolver); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
this.tokenProvider = this.kernel.getContainer().get( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,33 @@ | ||||||||||||||||||||||||
import { express } from "@/deps.ts"; | ||||||||||||||||||||||||
import { ConfigInterfaceResolver, inject, injectable, proxy } from "@/ilos/common/index.ts"; | ||||||||||||||||||||||||
import { asyncHandler } from "@/pdc/proxy/helpers/asyncHandler.ts"; | ||||||||||||||||||||||||
import { OidcCallbackAction } from "@/pdc/services/auth/actions/OidcCallbackAction.ts"; | ||||||||||||||||||||||||
import { OidcProvider } from "@/pdc/services/auth/providers/OidcProvider.ts"; | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
@injectable() | ||||||||||||||||||||||||
export class AuthRouter { | ||||||||||||||||||||||||
constructor( | ||||||||||||||||||||||||
@inject(proxy) private app: express.Express, | ||||||||||||||||||||||||
private oidcProvider: OidcProvider, | ||||||||||||||||||||||||
private oidcCallbackAction: OidcCallbackAction, | ||||||||||||||||||||||||
private config: ConfigInterfaceResolver, | ||||||||||||||||||||||||
) {} | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
register() { | ||||||||||||||||||||||||
this.app.get("/auth/login", (req, res, next) => { | ||||||||||||||||||||||||
return res.redirect(this.oidcProvider.getLoginUrl()); | ||||||||||||||||||||||||
}); | ||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add error handling and CSRF protection to the login route.
- this.app.get("/auth/login", (req, res, next) => {
+ this.app.get("/auth/login", csrfProtection, (req, res) => {
+ try {
return res.redirect(this.oidcProvider.getLoginUrl());
+ } catch (error) {
+ console.error('Login error:', error);
+ return res.status(500).json({ error: 'Login failed' });
+ }
}); 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||
|
||||||||||||||||||||||||
this.app.get( | ||||||||||||||||||||||||
"/auth/callback", | ||||||||||||||||||||||||
asyncHandler(async (req: express.Request, res: express.Response) => { | ||||||||||||||||||||||||
const { code } = req.query; | ||||||||||||||||||||||||
if (typeof code === "string") { | ||||||||||||||||||||||||
const user = await this.oidcCallbackAction.handle({ code }); | ||||||||||||||||||||||||
req.session.user = user; | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
return res.redirect(this.config.get("oidc.app_url")); | ||||||||||||||||||||||||
}), | ||||||||||||||||||||||||
); | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { router, serviceProvider } from "@/ilos/common/index.ts"; | ||
import { ServiceProvider as AbstractServiceProvider } from "@/ilos/core/index.ts"; | ||
import { ValidatorMiddleware } from "@/pdc/providers/superstruct/ValidatorMiddleware.ts"; | ||
|
||
import { OidcProvider } from "@/pdc/services/auth/providers/OidcProvider.ts"; | ||
import { OidcCallbackAction } from "./actions/OidcCallbackAction.ts"; | ||
import { AuthRouter } from "./AuthRouter.ts"; | ||
import { config } from "./config/index.ts"; | ||
import { UserRepository } from "./providers/UserRepository.ts"; | ||
|
||
@serviceProvider({ | ||
config, | ||
providers: [ | ||
UserRepository, | ||
OidcProvider, | ||
[router, AuthRouter], | ||
], | ||
middlewares: [ | ||
["validate", ValidatorMiddleware], | ||
], | ||
handlers: [OidcCallbackAction], | ||
}) | ||
export class AuthServiceProvider extends AbstractServiceProvider {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { ConfigInterfaceResolver, handler, UnauthorizedException } from "@/ilos/common/index.ts"; | ||
import { Action as AbstractAction } from "@/ilos/core/index.ts"; | ||
import { OidcCallback } from "../dto/OidcCallback.ts"; | ||
import { OidcProvider } from "../providers/OidcProvider.ts"; | ||
import { UserRepository } from "../providers/UserRepository.ts"; | ||
|
||
export type ResultInterface = { | ||
email: string; | ||
role: string; | ||
permissions: Array<string>; | ||
operator_id?: number; | ||
territory_id?: number; | ||
}; | ||
|
||
@handler({ | ||
service: "auth", | ||
method: "oidcCallback", | ||
middlewares: [ | ||
["validate", OidcCallback], | ||
], | ||
}) | ||
export class OidcCallbackAction extends AbstractAction { | ||
constructor( | ||
private oidcProvider: OidcProvider, | ||
private userRepository: UserRepository, | ||
protected config: ConfigInterfaceResolver, | ||
) { | ||
super(); | ||
} | ||
|
||
public async handle(params: OidcCallback): Promise<ResultInterface> { | ||
const token = await this.oidcProvider.getTokenFromCode(params.code); | ||
const info = await this.oidcProvider.getUserInfoFromToken(token); | ||
const user = await this.userRepository.findUserByEmail(info.email); | ||
if (!user || user.siret !== info.siret) { | ||
throw new UnauthorizedException("User not found"); | ||
} | ||
return { | ||
...user, | ||
permissions: this.getPermissionsFromRole(user.role), | ||
}; | ||
} | ||
|
||
private getPermissionsFromRole(role: string): string[] { | ||
return this.config.get(`permissions.${role}.permissions`, []); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import * as oidc from "./oidc.ts"; | ||
import * as permissions from "./permissions.ts"; | ||
|
||
export const config = { | ||
permissions, | ||
oidc, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import { env_or_fail } from "@/lib/env/index.ts"; | ||
export const client_id = env_or_fail("OIDC_CLIENT_ID"); | ||
export const client_secret = env_or_fail("OIDC_CLIENT_SECRET"); | ||
export const base_url = env_or_fail("OIDC_BASE_URL"); | ||
export const redirect_url = env_or_fail("OIDC_REDIRECT_URL"); | ||
export const app_url = env_or_fail("APP_APP_URL"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Verify the use of unstable-fs flag and add error handling.
The
debug
command uses the--unstable-fs
flag which is experimental and may change in future Deno releases. Additionally, consider adding error handling for failed imports.🌐 Web query:
💡 Result:
The
--unstable-fs
flag has been deprecated as of Deno 1.44 (May 2024) and is no longer required for core file system operations[1][4]. Key file system APIs previously behind this flag have been stabilized:Stabilized replacements include:
Deno.FsFile.syncData()
/syncDataSync()
for explicit file data synchronization[1]Deno.FsFile.sync()
/syncSync()
for metadata synchronization[1]Deno.FsFile.lock()
/lockSync()
andunlock()
/unlockSync()
for file locking[1]These changes eliminate previous compatibility issues with frameworks like Next.js while maintaining Deno's security model[1]. The stabilization means developers can now use these file system features without special flags:
For advanced filesystem access patterns beyond core operations, Deno recommends:
deno.land/x/fs
for extended utilities--compat
flag for npm package interoperability[2]While most filesystem features are now stable, some edge-case operations remain behind newer granular unstable flags like
--unstable-write
for experimental write optimizations[9]. The broader--unstable
flag itself is being phased out in favor of these targeted feature flags[9].Citations:
Action Required: Update debug command in
api/justfile
--unstable-fs
flag as it is no longer required (core file system operations are now stable since Deno 1.44).