Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.dbaagent.service.SystemConfigService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestClient;
Expand Down Expand Up @@ -34,6 +35,17 @@ public class SetupController {
private final CredentialRepository credentialRepository;
private final LlmConfigResolver llmConfigResolver;

/**
* Mirrors {@code security.google.enabled}. Surfaced on the public status
* endpoint so the login page can decide whether to offer Google sign-in —
* it is otherwise unauthenticated and has no way to know the server was
* configured for SSO. Deliberately NOT final: {@code @RequiredArgsConstructor}
* would pull a final field into the constructor and Spring has no bean to
* satisfy it.
*/
@Value("${security.google.enabled:false}")
private boolean googleEnabled;

// ── GET /setup/status ─────────────────────────────────────────────────────

/** Returns setup completion state. Public endpoint — no auth required. */
Expand All @@ -53,7 +65,8 @@ public SetupStatusResponse getStatus() {
setupComplete,
hasOrgInfo,
hasConnections,
hasLlmConfig
hasLlmConfig,
googleEnabled
);
}

Expand Down Expand Up @@ -278,7 +291,9 @@ public record SetupStatusResponse(
boolean setupComplete,
boolean hasOrganizationInfo,
boolean hasConnections,
boolean hasLlmConfig
boolean hasLlmConfig,
/** Whether Google Workspace SSO is configured; drives the login page's SSO button. */
boolean googleEnabled
) {}

public record InitializeRequest(String orgName, String adminUsername, String adminEmail, String adminPassword) {}
Expand Down
39 changes: 39 additions & 0 deletions src/pages/Login.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export default function Login() {


const renderLoginStep = () => (
<>
<form onSubmit={handlePasswordLogin} className="space-y-5">
<div>
<label htmlFor="email" className="text-xs font-semibold text-gray-500 uppercase tracking-wider block mb-1.5">
Expand Down Expand Up @@ -147,6 +148,44 @@ export default function Login() {
{loading ? 'Signing in…' : 'Sign In'}
</button>
</form>

{/*
Only rendered when the server reports security.google.enabled. The login
page is unauthenticated, so /setup/status (already public, already fetched
above) is how it learns SSO exists — otherwise this button would 500 for
every install that never configured Google.

A plain <a>, not a button: /api/auth/google/start issues a 302 to Google,
so this is a full-page navigation and must not submit the form above.
*/}
{setupStatus?.googleEnabled && (
<div className="mt-6">
<div className="relative">
<div className="absolute inset-0 flex items-center" aria-hidden="true">
<div className="w-full border-t border-gray-200" />
</div>
<div className="relative flex justify-center">
<span className="bg-white px-3 text-xs font-medium uppercase tracking-wider text-gray-400">
or
</span>
</div>
</div>

<a
href={authAPI.getGoogleStartUrl()}
className="mt-6 w-full min-h-[48px] flex items-center justify-center gap-3 bg-white border border-gray-300 hover:bg-gray-50 text-gray-700 font-semibold py-3 rounded-full shadow-sm transition-all active:scale-[0.98]"
>
<svg className="h-5 w-5" viewBox="0 0 24 24" aria-hidden="true">
<path fill="#4285F4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 0 1-2.2 3.32v2.76h3.57c2.08-1.92 3.28-4.74 3.28-8.09z" />
<path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.76c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84A11 11 0 0 0 12 23z" />
<path fill="#FBBC05" d="M5.84 14.11a6.6 6.6 0 0 1 0-4.22V7.05H2.18a11 11 0 0 0 0 9.9l3.66-2.84z" />
<path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1a11 11 0 0 0-9.82 6.05l3.66 2.84c.87-2.6 3.3-4.51 6.16-4.51z" />
</svg>
Sign in with Google
</a>
</div>
)}
</>
)

const renderOtpStep = () => (
Expand Down
Loading