update api users and groups and users 3
This commit is contained in:
parent
aa76772c61
commit
22bab9e845
@ -2,20 +2,8 @@ import { getServerSession } from "next-auth/next";
|
|||||||
import { authOptions } from "@/app/api/auth/[...nextauth]/route";
|
import { authOptions } from "@/app/api/auth/[...nextauth]/route";
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
|
|
||||||
export async function PUT(
|
async function getAdminToken() {
|
||||||
req: Request,
|
|
||||||
{ params }: { params: { userId: string } }
|
|
||||||
) {
|
|
||||||
const session = await getServerSession(authOptions);
|
|
||||||
|
|
||||||
if (!session) {
|
|
||||||
return NextResponse.json({ error: "Non autorisé" }, { status: 401 });
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { roles } = await req.json();
|
|
||||||
|
|
||||||
// Get client credentials token
|
|
||||||
const tokenResponse = await fetch(
|
const tokenResponse = await fetch(
|
||||||
`${process.env.KEYCLOAK_BASE_URL}/realms/${process.env.KEYCLOAK_REALM}/protocol/openid-connect/token`,
|
`${process.env.KEYCLOAK_BASE_URL}/realms/${process.env.KEYCLOAK_REALM}/protocol/openid-connect/token`,
|
||||||
{
|
{
|
||||||
@ -31,62 +19,132 @@ export async function PUT(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const tokenData = await tokenResponse.json();
|
const data = await tokenResponse.json();
|
||||||
|
|
||||||
if (!tokenResponse.ok) {
|
if (!tokenResponse.ok || !data.access_token) {
|
||||||
console.error("Failed to get token:", tokenData);
|
console.error('Token Error:', data);
|
||||||
return NextResponse.json({ error: "Failed to get token" }, { status: 500 });
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get available roles
|
return data.access_token;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Token Error:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function PUT(
|
||||||
|
req: Request,
|
||||||
|
{ params }: { params: { userId: string } }
|
||||||
|
) {
|
||||||
|
const session = await getServerSession(authOptions);
|
||||||
|
|
||||||
|
if (!session) {
|
||||||
|
return NextResponse.json({ error: "Non autorisé" }, { status: 401 });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { roles } = await req.json();
|
||||||
|
const token = await getAdminToken();
|
||||||
|
|
||||||
|
if (!token) {
|
||||||
|
return NextResponse.json({ error: "Erreur d'authentification" }, { status: 401 });
|
||||||
|
}
|
||||||
|
|
||||||
|
// First, get all available roles from Keycloak
|
||||||
const rolesResponse = await fetch(
|
const rolesResponse = await fetch(
|
||||||
`${process.env.KEYCLOAK_BASE_URL}/admin/realms/${process.env.KEYCLOAK_REALM}/roles`,
|
`${process.env.KEYCLOAK_BASE_URL}/admin/realms/${process.env.KEYCLOAK_REALM}/roles`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': `Bearer ${tokenData.access_token}`,
|
Authorization: `Bearer ${token}`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!rolesResponse.ok) {
|
if (!rolesResponse.ok) {
|
||||||
const errorData = await rolesResponse.json();
|
const errorData = await rolesResponse.json();
|
||||||
console.error("Failed to get roles:", errorData);
|
console.error("Failed to fetch roles:", errorData);
|
||||||
return NextResponse.json({ error: "Failed to get roles" }, { status: rolesResponse.status });
|
return NextResponse.json({ error: "Erreur lors de la récupération des rôles" }, { status: rolesResponse.status });
|
||||||
}
|
}
|
||||||
|
|
||||||
const availableRoles = await rolesResponse.json();
|
const availableRoles = await rolesResponse.json();
|
||||||
|
console.log("Available roles:", availableRoles);
|
||||||
|
|
||||||
// Map role names to role objects
|
// Map role names to role objects
|
||||||
const roleObjects = roles.map((roleName: string) => {
|
const roleObjects = roles.map((roleName: string) => {
|
||||||
const role = availableRoles.find((r: any) => r.name === roleName);
|
const role = availableRoles.find((r: any) => r.name === roleName);
|
||||||
if (!role) {
|
if (!role) {
|
||||||
throw new Error(`Role ${roleName} not found`);
|
throw new Error(`Role ${roleName} not found in Keycloak`);
|
||||||
}
|
}
|
||||||
return role;
|
return role;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update user roles
|
// First, get current role mappings
|
||||||
const updateResponse = await fetch(
|
const currentMappingsResponse = await fetch(
|
||||||
|
`${process.env.KEYCLOAK_BASE_URL}/admin/realms/${process.env.KEYCLOAK_REALM}/users/${params.userId}/role-mappings/realm`,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!currentMappingsResponse.ok) {
|
||||||
|
const errorData = await currentMappingsResponse.json();
|
||||||
|
console.error("Failed to fetch current role mappings:", errorData);
|
||||||
|
return NextResponse.json({ error: "Erreur lors de la récupération des rôles actuels" }, { status: currentMappingsResponse.status });
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentMappings = await currentMappingsResponse.json();
|
||||||
|
|
||||||
|
// Remove all current role mappings
|
||||||
|
if (currentMappings.length > 0) {
|
||||||
|
const deleteResponse = await fetch(
|
||||||
|
`${process.env.KEYCLOAK_BASE_URL}/admin/realms/${process.env.KEYCLOAK_REALM}/users/${params.userId}/role-mappings/realm`,
|
||||||
|
{
|
||||||
|
method: 'DELETE',
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(currentMappings),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!deleteResponse.ok) {
|
||||||
|
const errorData = await deleteResponse.json();
|
||||||
|
console.error("Failed to remove current roles:", errorData);
|
||||||
|
return NextResponse.json({ error: "Erreur lors de la suppression des rôles actuels" }, { status: deleteResponse.status });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add new role mappings
|
||||||
|
if (roleObjects.length > 0) {
|
||||||
|
const addResponse = await fetch(
|
||||||
`${process.env.KEYCLOAK_BASE_URL}/admin/realms/${process.env.KEYCLOAK_REALM}/users/${params.userId}/role-mappings/realm`,
|
`${process.env.KEYCLOAK_BASE_URL}/admin/realms/${process.env.KEYCLOAK_REALM}/users/${params.userId}/role-mappings/realm`,
|
||||||
{
|
{
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': `Bearer ${tokenData.access_token}`,
|
Authorization: `Bearer ${token}`,
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: JSON.stringify(roleObjects),
|
body: JSON.stringify(roleObjects),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!updateResponse.ok) {
|
if (!addResponse.ok) {
|
||||||
const errorData = await updateResponse.json();
|
const errorData = await addResponse.json();
|
||||||
console.error("Failed to update roles:", errorData);
|
console.error("Failed to add new roles:", errorData);
|
||||||
return NextResponse.json({ error: "Failed to update roles" }, { status: updateResponse.status });
|
return NextResponse.json({ error: "Erreur lors de l'ajout des nouveaux rôles" }, { status: addResponse.status });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NextResponse.json({ success: true });
|
return NextResponse.json({ success: true, roles });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error in update roles:", error);
|
console.error("Error in update roles:", error);
|
||||||
return NextResponse.json({ error: "Internal server error" }, { status: 500 });
|
return NextResponse.json(
|
||||||
|
{ error: error instanceof Error ? error.message : "Une erreur est survenue" },
|
||||||
|
{ status: 500 }
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -144,18 +144,8 @@ function getCurrentUser(session: any) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function POST(req: Request) {
|
async function getAdminToken() {
|
||||||
const session = await getServerSession(authOptions);
|
|
||||||
|
|
||||||
if (!session) {
|
|
||||||
return NextResponse.json({ error: "Non autorisé" }, { status: 401 });
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data = await req.json();
|
|
||||||
console.log("Creating user:", data);
|
|
||||||
|
|
||||||
// First get an admin token using client credentials
|
|
||||||
const tokenResponse = await fetch(
|
const tokenResponse = await fetch(
|
||||||
`${process.env.KEYCLOAK_BASE_URL}/realms/${process.env.KEYCLOAK_REALM}/protocol/openid-connect/token`,
|
`${process.env.KEYCLOAK_BASE_URL}/realms/${process.env.KEYCLOAK_REALM}/protocol/openid-connect/token`,
|
||||||
{
|
{
|
||||||
@ -171,37 +161,92 @@ export async function POST(req: Request) {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const tokenData = await tokenResponse.json();
|
const data = await tokenResponse.json();
|
||||||
|
|
||||||
if (!tokenResponse.ok) {
|
if (!tokenResponse.ok || !data.access_token) {
|
||||||
console.error("Failed to get admin token:", tokenData);
|
console.error('Token Error:', data);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data.access_token;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Token Error:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function POST(req: Request) {
|
||||||
|
const session = await getServerSession(authOptions);
|
||||||
|
|
||||||
|
if (!session) {
|
||||||
|
return NextResponse.json({ error: "Non autorisé" }, { status: 401 });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const data = await req.json();
|
||||||
|
console.log("Creating user:", data);
|
||||||
|
|
||||||
|
const token = await getAdminToken();
|
||||||
|
if (!token) {
|
||||||
|
return NextResponse.json({ error: "Erreur d'authentification" }, { status: 401 });
|
||||||
|
}
|
||||||
|
|
||||||
|
// First, get all available roles from Keycloak
|
||||||
|
const rolesResponse = await fetch(
|
||||||
|
`${process.env.KEYCLOAK_BASE_URL}/admin/realms/${process.env.KEYCLOAK_REALM}/roles`,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!rolesResponse.ok) {
|
||||||
|
const errorData = await rolesResponse.json();
|
||||||
|
console.error("Failed to fetch roles:", errorData);
|
||||||
|
return NextResponse.json({ error: "Erreur lors de la récupération des rôles" }, { status: rolesResponse.status });
|
||||||
|
}
|
||||||
|
|
||||||
|
const availableRoles = await rolesResponse.json();
|
||||||
|
console.log("Available roles:", availableRoles);
|
||||||
|
|
||||||
|
// Verify that the requested roles exist
|
||||||
|
const requestedRoles = data.roles || [];
|
||||||
|
const validRoles = requestedRoles.filter((roleName: string) =>
|
||||||
|
availableRoles.some((r: any) => r.name === roleName)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (validRoles.length === 0) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ error: "Erreur d'authentification" },
|
{ error: "Aucun rôle valide n'a été spécifié" },
|
||||||
{ status: 401 }
|
{ status: 400 }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format user data for Keycloak
|
// Create the user
|
||||||
const keycloakUser = {
|
const createResponse = await fetch(
|
||||||
|
`${process.env.KEYCLOAK_BASE_URL}/admin/realms/${process.env.KEYCLOAK_REALM}/users`,
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
username: data.username,
|
username: data.username,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
emailVerified: true,
|
emailVerified: true,
|
||||||
firstName: data.firstName,
|
firstName: data.firstName,
|
||||||
lastName: data.lastName,
|
lastName: data.lastName,
|
||||||
email: data.email,
|
email: data.email,
|
||||||
groups: [data.realmRoles], // Use groups instead of roles
|
credentials: [
|
||||||
};
|
|
||||||
|
|
||||||
// Create user in Keycloak using admin token
|
|
||||||
const createResponse = await fetch(
|
|
||||||
`${process.env.KEYCLOAK_BASE_URL}/admin/realms/${process.env.KEYCLOAK_REALM}/users`,
|
|
||||||
{
|
{
|
||||||
method: "POST",
|
type: "password",
|
||||||
headers: {
|
value: data.password,
|
||||||
Authorization: `Bearer ${tokenData.access_token}`,
|
temporary: false,
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
},
|
||||||
body: JSON.stringify(keycloakUser),
|
],
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -212,7 +257,7 @@ export async function POST(req: Request) {
|
|||||||
|
|
||||||
if (!createResponse.ok) {
|
if (!createResponse.ok) {
|
||||||
const errorData = await createResponse.json();
|
const errorData = await createResponse.json();
|
||||||
console.log("Keycloak error:", errorData);
|
console.error("Keycloak error:", errorData);
|
||||||
|
|
||||||
if (errorData.errorMessage?.includes("User exists with same username")) {
|
if (errorData.errorMessage?.includes("User exists with same username")) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
@ -236,7 +281,7 @@ export async function POST(req: Request) {
|
|||||||
`${process.env.KEYCLOAK_BASE_URL}/admin/realms/${process.env.KEYCLOAK_REALM}/users?username=${data.username}`,
|
`${process.env.KEYCLOAK_BASE_URL}/admin/realms/${process.env.KEYCLOAK_REALM}/users?username=${data.username}`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokenData.access_token}`,
|
Authorization: `Bearer ${token}`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -251,22 +296,37 @@ export async function POST(req: Request) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add user to group
|
// Add roles to the user
|
||||||
await fetch(
|
const roleObjects = validRoles.map((roleName: string) =>
|
||||||
`${process.env.KEYCLOAK_BASE_URL}/admin/realms/${process.env.KEYCLOAK_REALM}/users/${user.id}/groups/${data.realmRoles}`,
|
availableRoles.find((r: any) => r.name === roleName)
|
||||||
|
);
|
||||||
|
|
||||||
|
const roleResponse = await fetch(
|
||||||
|
`${process.env.KEYCLOAK_BASE_URL}/admin/realms/${process.env.KEYCLOAK_REALM}/users/${user.id}/role-mappings/realm`,
|
||||||
{
|
{
|
||||||
method: "PUT",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokenData.access_token}`,
|
Authorization: `Bearer ${token}`,
|
||||||
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
|
body: JSON.stringify(roleObjects),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!roleResponse.ok) {
|
||||||
|
const errorData = await roleResponse.json();
|
||||||
|
console.error("Failed to add roles:", errorData);
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "Erreur lors de l'ajout des rôles", details: errorData },
|
||||||
|
{ status: 500 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
success: true,
|
success: true,
|
||||||
user: {
|
user: {
|
||||||
...user,
|
...user,
|
||||||
roles: [data.realmRoles],
|
roles: validRoles,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user