281 lines
8.2 KiB
TypeScript
281 lines
8.2 KiB
TypeScript
import { getServerSession } from "next-auth/next";
|
|
import { authOptions } from "@/app/api/auth/[...nextauth]/route";
|
|
import { NextResponse } from "next/server";
|
|
|
|
export async function GET() {
|
|
const session = await getServerSession(authOptions);
|
|
|
|
if (!session) {
|
|
return NextResponse.json({ error: "Non autorisé" }, { status: 401 });
|
|
}
|
|
|
|
console.log("Session:", {
|
|
accessToken: session.accessToken?.substring(0, 20) + "...",
|
|
user: session.user,
|
|
});
|
|
|
|
try {
|
|
// Get client credentials token
|
|
const tokenResponse = await fetch(
|
|
`${process.env.KEYCLOAK_BASE_URL}/realms/${process.env.KEYCLOAK_REALM}/protocol/openid-connect/token`,
|
|
{
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
},
|
|
body: new URLSearchParams({
|
|
grant_type: 'client_credentials',
|
|
client_id: process.env.KEYCLOAK_CLIENT_ID!,
|
|
client_secret: process.env.KEYCLOAK_CLIENT_SECRET!,
|
|
}),
|
|
}
|
|
);
|
|
|
|
const tokenData = await tokenResponse.json();
|
|
console.log("Token response:", {
|
|
ok: tokenResponse.ok,
|
|
status: tokenResponse.status,
|
|
data: tokenData.access_token ? "Token received" : tokenData,
|
|
});
|
|
|
|
if (!tokenResponse.ok) {
|
|
console.error("Failed to get token:", tokenData);
|
|
return NextResponse.json([getCurrentUser(session)]);
|
|
}
|
|
|
|
// Get users list with brief=false to get full user details
|
|
const usersResponse = await fetch(
|
|
`${process.env.KEYCLOAK_BASE_URL}/admin/realms/${process.env.KEYCLOAK_REALM}/users?briefRepresentation=false`,
|
|
{
|
|
headers: {
|
|
Authorization: `Bearer ${tokenData.access_token}`,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
}
|
|
);
|
|
|
|
if (!usersResponse.ok) {
|
|
console.error("Failed to fetch users:", await usersResponse.text());
|
|
return NextResponse.json([getCurrentUser(session)]);
|
|
}
|
|
|
|
const users = await usersResponse.json();
|
|
console.log("Raw users data:", users.map((u: any) => ({
|
|
id: u.id,
|
|
username: u.username,
|
|
realm: u.realm,
|
|
serviceAccountClientId: u.serviceAccountClientId,
|
|
})));
|
|
|
|
// Filter out service accounts and users from other realms
|
|
const filteredUsers = users.filter((user: any) =>
|
|
!user.serviceAccountClientId && // Remove service accounts
|
|
(!user.realm || user.realm === process.env.KEYCLOAK_REALM) // Only users from our realm
|
|
);
|
|
|
|
console.log("Filtered users count:", filteredUsers.length);
|
|
|
|
// Fetch groups for each user
|
|
const usersWithGroups = await Promise.all(filteredUsers.map(async (user: any) => {
|
|
try {
|
|
const groupsResponse = await fetch(
|
|
`${process.env.KEYCLOAK_BASE_URL}/admin/realms/${process.env.KEYCLOAK_REALM}/users/${user.id}/groups`,
|
|
{
|
|
headers: {
|
|
Authorization: `Bearer ${tokenData.access_token}`,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
}
|
|
);
|
|
|
|
let groups = [];
|
|
if (groupsResponse.ok) {
|
|
const groupsData = await groupsResponse.json();
|
|
groups = groupsData.map((group: any) => group.name);
|
|
console.log(`Groups for user ${user.username}:`, groups);
|
|
}
|
|
|
|
return {
|
|
id: user.id,
|
|
username: user.username,
|
|
firstName: user.firstName || '',
|
|
lastName: user.lastName || '',
|
|
email: user.email,
|
|
createdTimestamp: user.createdTimestamp,
|
|
roles: groups,
|
|
};
|
|
} catch (error) {
|
|
console.error(`Error fetching groups for user ${user.id}:`, error);
|
|
return {
|
|
id: user.id,
|
|
username: user.username,
|
|
firstName: user.firstName || '',
|
|
lastName: user.lastName || '',
|
|
email: user.email,
|
|
createdTimestamp: user.createdTimestamp,
|
|
roles: [],
|
|
};
|
|
}
|
|
}));
|
|
|
|
console.log("Final users data:", usersWithGroups.map(u => ({
|
|
username: u.username,
|
|
roles: u.roles,
|
|
})));
|
|
|
|
return NextResponse.json(usersWithGroups);
|
|
|
|
} catch (error) {
|
|
console.error("Error:", error);
|
|
return NextResponse.json([getCurrentUser(session)]);
|
|
}
|
|
}
|
|
|
|
// Helper function to get current user data
|
|
function getCurrentUser(session: any) {
|
|
return {
|
|
id: session.user.id,
|
|
username: session.user.username,
|
|
firstName: session.user.first_name,
|
|
lastName: session.user.last_name,
|
|
email: session.user.email,
|
|
createdTimestamp: Date.now(),
|
|
roles: session.user.role || [],
|
|
};
|
|
}
|
|
|
|
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);
|
|
|
|
// First get an admin token using client credentials
|
|
const tokenResponse = await fetch(
|
|
`${process.env.KEYCLOAK_BASE_URL}/realms/${process.env.KEYCLOAK_REALM}/protocol/openid-connect/token`,
|
|
{
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
},
|
|
body: new URLSearchParams({
|
|
grant_type: 'client_credentials',
|
|
client_id: process.env.KEYCLOAK_CLIENT_ID!,
|
|
client_secret: process.env.KEYCLOAK_CLIENT_SECRET!,
|
|
}),
|
|
}
|
|
);
|
|
|
|
const tokenData = await tokenResponse.json();
|
|
|
|
if (!tokenResponse.ok) {
|
|
console.error("Failed to get admin token:", tokenData);
|
|
return NextResponse.json(
|
|
{ error: "Erreur d'authentification" },
|
|
{ status: 401 }
|
|
);
|
|
}
|
|
|
|
// Format user data for Keycloak
|
|
const keycloakUser = {
|
|
username: data.username,
|
|
enabled: true,
|
|
emailVerified: true,
|
|
firstName: data.firstName,
|
|
lastName: data.lastName,
|
|
email: data.email,
|
|
groups: [data.realmRoles], // Use groups instead of roles
|
|
};
|
|
|
|
// 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",
|
|
headers: {
|
|
Authorization: `Bearer ${tokenData.access_token}`,
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify(keycloakUser),
|
|
}
|
|
);
|
|
|
|
console.log("Keycloak create response:", {
|
|
status: createResponse.status,
|
|
ok: createResponse.ok
|
|
});
|
|
|
|
if (!createResponse.ok) {
|
|
const errorData = await createResponse.json();
|
|
console.log("Keycloak error:", errorData);
|
|
|
|
if (errorData.errorMessage?.includes("User exists with same username")) {
|
|
return NextResponse.json(
|
|
{ error: "Un utilisateur existe déjà avec ce nom d'utilisateur" },
|
|
{ status: 400 }
|
|
);
|
|
} else if (errorData.errorMessage?.includes("User exists with same email")) {
|
|
return NextResponse.json(
|
|
{ error: "Un utilisateur existe déjà avec cet email" },
|
|
{ status: 400 }
|
|
);
|
|
}
|
|
return NextResponse.json(
|
|
{ error: "Erreur création utilisateur", details: errorData },
|
|
{ status: 400 }
|
|
);
|
|
}
|
|
|
|
// Get the created user
|
|
const userResponse = await fetch(
|
|
`${process.env.KEYCLOAK_BASE_URL}/admin/realms/${process.env.KEYCLOAK_REALM}/users?username=${data.username}`,
|
|
{
|
|
headers: {
|
|
Authorization: `Bearer ${tokenData.access_token}`,
|
|
},
|
|
}
|
|
);
|
|
|
|
const users = await userResponse.json();
|
|
const user = users[0];
|
|
|
|
if (!user) {
|
|
return NextResponse.json(
|
|
{ error: "Utilisateur créé mais impossible de le récupérer" },
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
|
|
// Add user to group
|
|
await fetch(
|
|
`${process.env.KEYCLOAK_BASE_URL}/admin/realms/${process.env.KEYCLOAK_REALM}/users/${user.id}/groups/${data.realmRoles}`,
|
|
{
|
|
method: "PUT",
|
|
headers: {
|
|
Authorization: `Bearer ${tokenData.access_token}`,
|
|
},
|
|
}
|
|
);
|
|
|
|
return NextResponse.json({
|
|
success: true,
|
|
user: {
|
|
...user,
|
|
roles: [data.realmRoles],
|
|
},
|
|
});
|
|
|
|
} catch (error) {
|
|
console.error("Error creating user:", error);
|
|
return NextResponse.json(
|
|
{ error: "Erreur serveur", details: error },
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
}
|