-
Notifications
You must be signed in to change notification settings - Fork 0
ACHOO-146: AuthZ #28
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
ACHOO-146: AuthZ #28
Changes from all commits
ae96015
54d7599
ded1b24
66148b6
70d54fd
732e03c
1f3a8f5
d2507a9
0f503a9
e913d87
384d45c
44b6b9f
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 |
|---|---|---|
|
|
@@ -44,3 +44,6 @@ next-env.d.ts | |
| # saml | ||
| saml-sp.key | ||
| saml-sp.crt | ||
|
|
||
| # Cache directory, if present | ||
| .cache | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,9 @@ | ||
| import { NextRequest, NextResponse } from 'next/server'; | ||
| import AcquiaApiServiceFixed from '@/lib/acquia-api'; | ||
| import { withApiAuthorization } from '@/lib/api-auth'; | ||
|
|
||
| export async function GET(request: NextRequest) { | ||
| return withApiAuthorization(async (request: NextRequest, context: { user: any }) => { | ||
|
||
| // console.log('🚀 Applications API Route called'); | ||
|
|
||
| // Update the API service initialization with better error handling | ||
|
|
@@ -55,4 +57,5 @@ export async function GET(request: NextRequest) { | |
| { status: 500 } | ||
| ); | ||
| } | ||
| })(request); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,27 +1,29 @@ | ||
| import { NextRequest, NextResponse } from 'next/server'; | ||
| import AcquiaApiServiceFixed from '@/lib/acquia-api'; | ||
| import { withApiAuthorization } from '@/lib/api-auth'; | ||
|
|
||
| export async function GET(request: NextRequest) { | ||
| const searchParams = request.nextUrl.searchParams; | ||
| const subscriptionUuid = searchParams.get('subscriptionUuid'); | ||
| const from = searchParams.get('from'); | ||
| const to = searchParams.get('to'); | ||
| const resolution = searchParams.get('resolution'); // Get granularity for daily data | ||
| /** | ||
| console.log('🚀 Views by Application API Route called with params:', { | ||
| subscriptionUuid, | ||
| from, | ||
| to, | ||
| resolution | ||
| }); | ||
| */ | ||
| if (!subscriptionUuid) { | ||
| console.error('❌ Missing required parameter: subscriptionUuid'); | ||
| return NextResponse.json( | ||
| { error: 'subscriptionUuid is required' }, | ||
| { status: 400 } | ||
| ); | ||
| } | ||
| return withApiAuthorization(async (request: NextRequest, context: { user: any }) => { | ||
|
||
| const searchParams = request.nextUrl.searchParams; | ||
| const subscriptionUuid = searchParams.get('subscriptionUuid'); | ||
| const from = searchParams.get('from'); | ||
| const to = searchParams.get('to'); | ||
| const resolution = searchParams.get('resolution'); // Get granularity for daily data | ||
| /** | ||
| console.log('🚀 Views by Application API Route called with params:', { | ||
| subscriptionUuid, | ||
| from, | ||
| to, | ||
| resolution | ||
| }); | ||
| */ | ||
| if (!subscriptionUuid) { | ||
| console.error('❌ Missing required parameter: subscriptionUuid'); | ||
| return NextResponse.json( | ||
| { error: 'subscriptionUuid is required' }, | ||
| { status: 400 } | ||
| ); | ||
| } | ||
|
Comment on lines
+6
to
+26
|
||
|
|
||
| if (!process.env.ACQUIA_API_KEY || !process.env.ACQUIA_API_SECRET) { | ||
| console.error('❌ Missing required environment variables!'); | ||
|
|
@@ -82,4 +84,5 @@ export async function GET(request: NextRequest) { | |
| { status: 500 } | ||
| ); | ||
| } | ||
| })(request); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,9 @@ | ||
| import { NextRequest, NextResponse } from 'next/server'; | ||
| import AcquiaApiServiceFixed from '@/lib/acquia-api'; | ||
| import { withApiAuthorization } from '@/lib/api-auth'; | ||
|
|
||
| export async function GET(request: NextRequest) { | ||
| return withApiAuthorization(async (request: NextRequest, context: { user: any }) => { | ||
|
||
| const searchParams = request.nextUrl.searchParams; | ||
| const subscriptionUuid = searchParams.get('subscriptionUuid'); | ||
| const from = searchParams.get('from'); | ||
|
|
@@ -85,4 +87,5 @@ export async function GET(request: NextRequest) { | |
| { status: 500 } | ||
| ); | ||
| } | ||
| })(request); | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -8,11 +8,22 @@ import { getBaseUrl } from '@/lib/url-utils' | |||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||
| export async function GET(request: NextRequest) { | ||||||||||||||||||||||||||||||||||||||||||||
| const cookieStore = await cookies() | ||||||||||||||||||||||||||||||||||||||||||||
| const { searchParams } = new URL(request.url) | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| // Delete the JWT cookie | ||||||||||||||||||||||||||||||||||||||||||||
| cookieStore.delete(getSessionCookieName()) | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| // Redirect to home page or login page | ||||||||||||||||||||||||||||||||||||||||||||
| // Check if redirect URL is specified (e.g., from test page) | ||||||||||||||||||||||||||||||||||||||||||||
| const redirectTo = searchParams.get('redirectTo') | ||||||||||||||||||||||||||||||||||||||||||||
| const baseUrl = getBaseUrl(request) | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| if (redirectTo) { | ||||||||||||||||||||||||||||||||||||||||||||
| // Validate that redirect is to a safe path (starts with /) | ||||||||||||||||||||||||||||||||||||||||||||
| if (redirectTo.startsWith('/')) { | ||||||||||||||||||||||||||||||||||||||||||||
| return NextResponse.redirect(new URL(redirectTo, baseUrl)) | ||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+21
to
+23
|
||||||||||||||||||||||||||||||||||||||||||||
| // Validate that redirect is to a safe path (starts with /) | |
| if (redirectTo.startsWith('/')) { | |
| return NextResponse.redirect(new URL(redirectTo, baseUrl)) | |
| // Validate that redirectTo is a safe, relative path (no protocol, no hostname, no double slashes, no backslashes) | |
| try { | |
| // Only allow relative paths that start with a single slash and do not contain suspicious patterns | |
| if ( | |
| redirectTo.startsWith('/') && | |
| !redirectTo.startsWith('//') && | |
| !redirectTo.startsWith('/\\') && | |
| !redirectTo.includes('\\') && | |
| !redirectTo.includes('..') // Prevent directory traversal | |
| ) { | |
| const url = new URL(redirectTo, baseUrl) | |
| // Ensure the redirect stays on the same origin | |
| if (url.origin === baseUrl) { | |
| return NextResponse.redirect(url) | |
| } | |
| } | |
| } catch (e) { | |
| // Ignore invalid URLs and fall through to default redirect |
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.
The documentation states that dashboard access requires "global OR any app" access, but the implementation in
hasDashboardAccessonly grants access to users with global access. This inconsistency means per-application users will be denied dashboard access despite documentation stating they should have it.Either update the implementation to allow per-app users to access the dashboard (showing only their authorized applications), or update the documentation to accurately reflect that only global access users can access the dashboard.