feat: Entra ID login + settings page for integrations
- Add SQLite settings table with getSetting/setSetting/getAllSettings helpers - Implement Azure OAuth2 authorization code flow via @azure/msal-node - Add public GET /api/auth/config endpoint for frontend activation check - Add admin-only GET/PUT /api/settings API with masked secret fields - CheckMK sync reads credentials from DB settings (env vars as fallback) - New Settings.tsx: Entra ID and CheckMK configuration cards - LoginPage: "Sign in with Microsoft" button, shown only when Azure is active - App.tsx: OAuth callback handling (?token=/?auth_error=), Settings tab for admins
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { GhostGridLogo } from './Header';
|
||||
import { authFetch, saveSession } from '../lib/auth';
|
||||
import { User } from '../types';
|
||||
@ -7,14 +7,23 @@ import { LogIn, Eye, EyeOff, AlertCircle } from 'lucide-react';
|
||||
interface LoginPageProps {
|
||||
onLogin: (user: User) => void;
|
||||
onNavigateToRegister: () => void;
|
||||
authError?: string;
|
||||
}
|
||||
|
||||
export default function LoginPage({ onLogin, onNavigateToRegister }: LoginPageProps) {
|
||||
export default function LoginPage({ onLogin, onNavigateToRegister, authError }: LoginPageProps) {
|
||||
const [email, setEmail] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
const [error, setError] = useState(authError || '');
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [azureEnabled, setAzureEnabled] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
fetch('/api/auth/config')
|
||||
.then(r => r.json())
|
||||
.then(d => setAzureEnabled(Boolean(d.azureEnabled)))
|
||||
.catch(() => {});
|
||||
}, []);
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
@ -137,6 +146,30 @@ export default function LoginPage({ onLogin, onNavigateToRegister }: LoginPagePr
|
||||
</button>
|
||||
</form>
|
||||
|
||||
{azureEnabled && (
|
||||
<>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex-1 h-px bg-slate-800" />
|
||||
<span className="text-[10px] font-mono text-slate-500 uppercase tracking-widest">oder</span>
|
||||
<div className="flex-1 h-px bg-slate-800" />
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => { window.location.href = '/api/auth/azure'; }}
|
||||
className="w-full flex items-center justify-center gap-3 bg-slate-800 hover:bg-slate-700 border border-slate-700 hover:border-slate-600 text-white font-semibold text-sm py-2.5 rounded-lg transition-all"
|
||||
>
|
||||
{/* Microsoft M logo */}
|
||||
<svg width="18" height="18" viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
||||
<rect x="1" y="1" width="9" height="9" fill="#F25022" />
|
||||
<rect x="11" y="1" width="9" height="9" fill="#7FBA00" />
|
||||
<rect x="1" y="11" width="9" height="9" fill="#00A4EF" />
|
||||
<rect x="11" y="11" width="9" height="9" fill="#FFB900" />
|
||||
</svg>
|
||||
Mit Microsoft anmelden
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
|
||||
<p className="text-center text-xs text-slate-400">
|
||||
No account yet?{' '}
|
||||
<button
|
||||
|
||||
Reference in New Issue
Block a user