- Simplified the application creation process by consolidating form fields and enhancing validation. - Updated the create application page to streamline user experience with clearer provider options and improved layout. - Implemented SweetAlert for success and error notifications during user actions, replacing traditional alerts. - Enhanced the applications index page with dynamic filtering and improved data fetching from the Authentik API. - Refactored API endpoints to utilize slugs for application identification, ensuring consistency with Authentik's structure. - Improved authentication handling by updating the requireAuth utility to support cookie-based authentication.
224 lines
8.7 KiB
JavaScript
224 lines
8.7 KiB
JavaScript
import { authentikFetch, clearAuthentikCache } from '../../utils/authentik';
|
|
import { requireAuth } from '../../utils/auth';
|
|
|
|
// Simplified /api/applications endpoint
|
|
export default defineEventHandler(async (event) => {
|
|
const method = getMethod(event);
|
|
|
|
switch (method) {
|
|
case 'GET':
|
|
// Public endpoint for listing applications
|
|
try {
|
|
const response = await authentikFetch('/core/applications/');
|
|
return response;
|
|
} catch (error) {
|
|
console.error('❌ Failed to fetch applications:', error.message);
|
|
throw error;
|
|
}
|
|
|
|
case 'POST':
|
|
// TODO: Add authentication later - for now make it public for testing
|
|
await requireAuth(event);
|
|
|
|
try {
|
|
const body = await readBody(event);
|
|
console.log(`🔨 Creating application: ${body.name} (${body.providerType})`);
|
|
|
|
// Simplified application creation - just the essentials
|
|
// Create application first
|
|
const applicationData = {
|
|
name: body.name,
|
|
slug: body.slug || body.name.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, ''),
|
|
meta_description: body.meta_description || body.description,
|
|
meta_publisher: body.meta_publisher || 'CorradAF RBAC',
|
|
meta_launch_url: body.meta_launch_url || body.launchUrl
|
|
};
|
|
|
|
let application;
|
|
try {
|
|
application = await authentikFetch('/core/applications/', {
|
|
method: 'POST',
|
|
body: applicationData
|
|
});
|
|
console.log('✅ Application created successfully');
|
|
} catch (appError) {
|
|
console.error('❌ Application creation failed:', appError.message);
|
|
if (appError.data) {
|
|
console.error('Details:', JSON.stringify(appError.data, null, 2));
|
|
}
|
|
throw appError;
|
|
}
|
|
|
|
// Create provider based on type (simplified presets)
|
|
if (body.providerType && application.pk) {
|
|
try {
|
|
console.log(`🔨 Creating ${body.providerType.toUpperCase()} provider...`);
|
|
|
|
// Get required flows for all providers
|
|
const flows = await authentikFetch('/flows/instances/');
|
|
|
|
// Find required flows
|
|
const authFlows = flows.results.filter(flow => flow.designation === 'authentication');
|
|
const invalidationFlows = flows.results.filter(flow => flow.designation === 'invalidation');
|
|
|
|
const defaultAuthFlow = authFlows.find(flow => flow.slug === 'default-authentication-flow') || authFlows[0];
|
|
const defaultInvalidationFlow = invalidationFlows.find(flow => flow.slug === 'default-invalidation-flow') || invalidationFlows[0];
|
|
|
|
if (!defaultAuthFlow) {
|
|
throw new Error('No authentication flow found - required for all providers');
|
|
}
|
|
|
|
|
|
let provider = null;
|
|
|
|
switch (body.providerType) {
|
|
case 'oauth2':
|
|
// OAuth2/OIDC provider preset
|
|
const oauth2Data = {
|
|
name: `${body.name} OAuth2`,
|
|
client_type: 'confidential',
|
|
authorization_flow: defaultAuthFlow.pk,
|
|
invalidation_flow: defaultInvalidationFlow?.pk,
|
|
redirect_uris: [
|
|
{
|
|
matching_mode: 'strict',
|
|
url: `${body.meta_launch_url || body.launchUrl}/auth/callback`
|
|
}
|
|
]
|
|
};
|
|
|
|
try {
|
|
provider = await authentikFetch('/providers/oauth2/', {
|
|
method: 'POST',
|
|
body: oauth2Data
|
|
});
|
|
console.log('✅ OAuth2 provider created');
|
|
} catch (oauth2Error) {
|
|
console.error('❌ OAuth2 provider failed:', oauth2Error.message);
|
|
if (oauth2Error.data) {
|
|
console.error('Details:', JSON.stringify(oauth2Error.data, null, 2));
|
|
}
|
|
throw oauth2Error;
|
|
}
|
|
break;
|
|
|
|
case 'saml':
|
|
// SAML provider preset
|
|
const samlData = {
|
|
name: `${body.name} SAML`,
|
|
acs_url: `${body.meta_launch_url || body.launchUrl}/saml/acs`,
|
|
audience: body.slug,
|
|
issuer: `corradaf-${body.slug}`,
|
|
sp_binding: 'post',
|
|
authorization_flow: defaultAuthFlow.pk,
|
|
invalidation_flow: defaultInvalidationFlow?.pk
|
|
};
|
|
|
|
try {
|
|
provider = await authentikFetch('/providers/saml/', {
|
|
method: 'POST',
|
|
body: samlData
|
|
});
|
|
console.log('✅ SAML provider created');
|
|
} catch (samlError) {
|
|
console.error('❌ SAML provider failed:', samlError.message);
|
|
if (samlError.data) {
|
|
console.error('Details:', JSON.stringify(samlError.data, null, 2));
|
|
}
|
|
throw samlError;
|
|
}
|
|
break;
|
|
|
|
case 'ldap':
|
|
// LDAP provider preset
|
|
const ldapData = {
|
|
name: `${body.name} LDAP`,
|
|
base_dn: 'dc=ldap,dc=goauthentik,dc=io',
|
|
authorization_flow: defaultAuthFlow.pk,
|
|
invalidation_flow: defaultInvalidationFlow?.pk
|
|
};
|
|
|
|
try {
|
|
provider = await authentikFetch('/providers/ldap/', {
|
|
method: 'POST',
|
|
body: ldapData
|
|
});
|
|
console.log('✅ LDAP provider created');
|
|
} catch (ldapError) {
|
|
console.error('❌ LDAP provider failed:', ldapError.message);
|
|
if (ldapError.data) {
|
|
console.error('Details:', JSON.stringify(ldapError.data, null, 2));
|
|
}
|
|
throw ldapError;
|
|
}
|
|
break;
|
|
|
|
case 'proxy':
|
|
// Proxy provider preset
|
|
const proxyData = {
|
|
name: `${body.name} Proxy`,
|
|
external_host: body.meta_launch_url || body.launchUrl,
|
|
internal_host: body.meta_launch_url || body.launchUrl,
|
|
authorization_flow: defaultAuthFlow.pk,
|
|
invalidation_flow: defaultInvalidationFlow?.pk
|
|
};
|
|
|
|
try {
|
|
provider = await authentikFetch('/providers/proxy/', {
|
|
method: 'POST',
|
|
body: proxyData
|
|
});
|
|
console.log('✅ Proxy provider created');
|
|
} catch (proxyError) {
|
|
console.error('❌ Proxy provider failed:', proxyError.message);
|
|
if (proxyError.data) {
|
|
console.error('Details:', JSON.stringify(proxyError.data, null, 2));
|
|
}
|
|
throw proxyError;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Link provider to application
|
|
if (provider && provider.pk) {
|
|
await authentikFetch(`/core/applications/${application.slug}/`, {
|
|
method: 'PATCH',
|
|
body: {
|
|
provider: provider.pk
|
|
}
|
|
});
|
|
console.log(`✅ ${body.providerType.toUpperCase()} provider linked to application`);
|
|
} else {
|
|
console.warn('⚠️ Provider was not created properly');
|
|
}
|
|
} catch (providerError) {
|
|
console.warn('⚠️ Provider creation failed, but application was created:', providerError.message);
|
|
// Don't fail the entire operation if provider creation fails
|
|
}
|
|
}
|
|
|
|
// Clear Authentik cache to ensure changes take effect immediately
|
|
try {
|
|
await clearAuthentikCache();
|
|
console.log('✅ Cache cleared after application creation');
|
|
} catch (cacheError) {
|
|
console.warn('⚠️ Cache clearing failed but application was created:', cacheError.message);
|
|
// Continue even if cache clearing fails
|
|
}
|
|
|
|
return {
|
|
...application,
|
|
message: 'Application created successfully'
|
|
};
|
|
} catch (error) {
|
|
console.error('❌ Failed to create application:', error.message);
|
|
throw error;
|
|
}
|
|
|
|
default:
|
|
throw createError({
|
|
statusCode: 405,
|
|
message: 'Method not allowed'
|
|
});
|
|
}
|
|
});
|