190 lines
6.6 KiB
TypeScript
190 lines
6.6 KiB
TypeScript
import { NextResponse } from "next/server";
|
|
import { getServerSession } from "next-auth";
|
|
import { authOptions } from "@/app/api/auth/[...nextauth]/route";
|
|
import { getKeycloakAdminClient } from "@/lib/keycloak";
|
|
|
|
// Fix for Next.js "params should be awaited" error
|
|
export const dynamic = 'force-dynamic';
|
|
|
|
export async function GET(
|
|
request: Request,
|
|
{ params }: { params: { userId?: string } }
|
|
) {
|
|
try {
|
|
const session = await getServerSession(authOptions);
|
|
if (!session) {
|
|
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
}
|
|
|
|
// Safely extract userId from params
|
|
const rawUserId = params?.userId;
|
|
const userId = typeof rawUserId === 'string' ? rawUserId : '';
|
|
|
|
if (!userId) {
|
|
return NextResponse.json({ error: "User ID is required" }, { status: 400 });
|
|
}
|
|
|
|
try {
|
|
// Check for required environment variables before attempting to connect
|
|
const missingVars = [];
|
|
if (!process.env.KEYCLOAK_BASE_URL && !process.env.KEYCLOAK_ISSUER && !process.env.NEXT_PUBLIC_KEYCLOAK_ISSUER) {
|
|
missingVars.push('KEYCLOAK_BASE_URL or KEYCLOAK_ISSUER');
|
|
}
|
|
if (!process.env.KEYCLOAK_CLIENT_ID) missingVars.push('KEYCLOAK_CLIENT_ID');
|
|
if (!process.env.KEYCLOAK_ADMIN_USERNAME) missingVars.push('KEYCLOAK_ADMIN_USERNAME');
|
|
if (!process.env.KEYCLOAK_ADMIN_PASSWORD) missingVars.push('KEYCLOAK_ADMIN_PASSWORD');
|
|
if (!process.env.KEYCLOAK_REALM) missingVars.push('KEYCLOAK_REALM');
|
|
|
|
// Note: Client secret might be required depending on client configuration
|
|
console.log('Keycloak client config:', {
|
|
clientId: process.env.KEYCLOAK_CLIENT_ID,
|
|
hasClientSecret: !!process.env.KEYCLOAK_CLIENT_SECRET,
|
|
username: process.env.KEYCLOAK_ADMIN_USERNAME,
|
|
realm: process.env.KEYCLOAK_REALM,
|
|
});
|
|
|
|
if (missingVars.length > 0) {
|
|
console.error(`Missing Keycloak environment variables: ${missingVars.join(', ')}`);
|
|
return NextResponse.json(
|
|
{
|
|
error: "Keycloak configuration incomplete",
|
|
message: "Role management is currently unavailable due to missing configuration.",
|
|
details: `Missing: ${missingVars.join(', ')}`
|
|
},
|
|
{ status: 503 }
|
|
);
|
|
}
|
|
|
|
const kcAdminClient = await getKeycloakAdminClient();
|
|
|
|
// Get all available roles
|
|
const availableRoles = await kcAdminClient.roles.find();
|
|
|
|
// Get user's current roles
|
|
const userRoles = await kcAdminClient.users.listRoleMappings({
|
|
id: userId,
|
|
});
|
|
|
|
return NextResponse.json({
|
|
availableRoles,
|
|
userRoles,
|
|
});
|
|
} catch (keycloakError) {
|
|
console.error("Error connecting to Keycloak:", keycloakError);
|
|
return NextResponse.json(
|
|
{ error: "Failed to connect to Keycloak service", details: String(keycloakError) },
|
|
{ status: 503 }
|
|
);
|
|
}
|
|
} catch (error) {
|
|
console.error("Error fetching roles:", error);
|
|
return NextResponse.json(
|
|
{ error: "Failed to fetch roles" },
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
}
|
|
|
|
export async function PUT(
|
|
request: Request,
|
|
{ params }: { params: { userId?: string } }
|
|
) {
|
|
try {
|
|
const session = await getServerSession(authOptions);
|
|
if (!session) {
|
|
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
}
|
|
|
|
// Safely extract userId from params
|
|
const rawUserId = params?.userId;
|
|
const userId = typeof rawUserId === 'string' ? rawUserId : '';
|
|
|
|
if (!userId) {
|
|
return NextResponse.json({ error: "User ID is required" }, { status: 400 });
|
|
}
|
|
|
|
try {
|
|
// Check for required environment variables before attempting to connect
|
|
const missingVars = [];
|
|
if (!process.env.KEYCLOAK_BASE_URL && !process.env.KEYCLOAK_ISSUER && !process.env.NEXT_PUBLIC_KEYCLOAK_ISSUER) {
|
|
missingVars.push('KEYCLOAK_BASE_URL or KEYCLOAK_ISSUER');
|
|
}
|
|
if (!process.env.KEYCLOAK_CLIENT_ID) missingVars.push('KEYCLOAK_CLIENT_ID');
|
|
if (!process.env.KEYCLOAK_ADMIN_USERNAME) missingVars.push('KEYCLOAK_ADMIN_USERNAME');
|
|
if (!process.env.KEYCLOAK_ADMIN_PASSWORD) missingVars.push('KEYCLOAK_ADMIN_PASSWORD');
|
|
if (!process.env.KEYCLOAK_REALM) missingVars.push('KEYCLOAK_REALM');
|
|
|
|
// Note: Client secret might be required depending on client configuration
|
|
console.log('Keycloak client config:', {
|
|
clientId: process.env.KEYCLOAK_CLIENT_ID,
|
|
hasClientSecret: !!process.env.KEYCLOAK_CLIENT_SECRET,
|
|
username: process.env.KEYCLOAK_ADMIN_USERNAME,
|
|
realm: process.env.KEYCLOAK_REALM,
|
|
});
|
|
|
|
if (missingVars.length > 0) {
|
|
console.error(`Missing Keycloak environment variables: ${missingVars.join(', ')}`);
|
|
return NextResponse.json(
|
|
{
|
|
error: "Keycloak configuration incomplete",
|
|
message: "Role management is currently unavailable due to missing configuration.",
|
|
details: `Missing: ${missingVars.join(', ')}`
|
|
},
|
|
{ status: 503 }
|
|
);
|
|
}
|
|
|
|
const { roles } = await request.json();
|
|
const kcAdminClient = await getKeycloakAdminClient();
|
|
|
|
// Get all available roles
|
|
const availableRoles = await kcAdminClient.roles.find();
|
|
|
|
// Get current user roles
|
|
const currentRoles = await kcAdminClient.users.listRoleMappings({
|
|
id: userId,
|
|
});
|
|
|
|
// Find roles to add and remove
|
|
const rolesToAdd = roles.filter(
|
|
(role: string) => !currentRoles.realmMappings?.some((r: any) => r.name === role)
|
|
);
|
|
const rolesToRemove = currentRoles.realmMappings?.filter(
|
|
(role: any) => !roles.includes(role.name)
|
|
);
|
|
|
|
// Add new roles
|
|
for (const roleName of rolesToAdd) {
|
|
const role = availableRoles.find((r: any) => r.name === roleName);
|
|
if (role) {
|
|
await kcAdminClient.users.addRealmRoleMappings({
|
|
id: userId,
|
|
roles: [role as any],
|
|
});
|
|
}
|
|
}
|
|
|
|
// Remove old roles
|
|
if (rolesToRemove && rolesToRemove.length > 0) {
|
|
await kcAdminClient.users.delRealmRoleMappings({
|
|
id: userId,
|
|
roles: rolesToRemove as any,
|
|
});
|
|
}
|
|
|
|
return NextResponse.json({ success: true });
|
|
} catch (keycloakError) {
|
|
console.error("Error connecting to Keycloak:", keycloakError);
|
|
return NextResponse.json(
|
|
{ error: "Failed to connect to Keycloak service", details: String(keycloakError) },
|
|
{ status: 503 }
|
|
);
|
|
}
|
|
} catch (error) {
|
|
console.error("Error updating roles:", error);
|
|
return NextResponse.json(
|
|
{ error: "Failed to update roles" },
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
}
|