mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-08-04 23:00:30 +08:00
feat: Add disable_password_login configuration to support SSO-only authentication (#13151)
### What problem does this PR solve? Enterprise deployments that use an external Identity Provider (e.g., Microsoft Entra ID, Okta, Keycloak) need the ability to enforce SSO-only authentication by hiding the email/password login form. Currently, the login page always shows the password form alongside OAuth buttons, with no way to disable it. This PR adds a `disable_password_login` configuration option under the existing `authentication` section in `service_conf.yaml`. When set to `true`, the login page only displays configured OAuth/SSO buttons and hides the email/password form, "Remember me" checkbox, and "Sign up" link. The flag can be set via: - `service_conf.yaml` (`authentication.disable_password_login: true`) - Environment variable (`DISABLE_PASSWORD_LOGIN=true`) Default behavior is unchanged (`false`). ### Behavior | `disable_password_login` | OAuth configured | Result | |---|---|---| | `false` (default) | No | Standard email/password form | | `false` | Yes | Email/password form + SSO buttons below | | `true` | Yes | **SSO buttons only** (no form, no sign up link) | | `true` | No | Empty card (admin should configure OAuth first) | ### Type of change - [x] New Feature (non-breaking change which adds functionality) ### Files changed (5) 1. `docker/service_conf.yaml.template` — added `disable_password_login: false` under authentication 2. `common/settings.py` — added `DISABLE_PASSWORD_LOGIN` global variable and loader in `init_settings()` 3. `common/config_utils.py` — fixed `TypeError` in `show_configs()` when authentication section contains non-dict values (e.g., booleans) 4. `api/apps/system_app.py` — exposed `disablePasswordLogin` flag in `/config` endpoint 5. `web/src/pages/login/index.tsx` — conditionally render password form based on config flag; OAuth buttons always render when channels exist --------- Co-authored-by: Ahmad Intisar <ahmadintisar@Ahmads-MacBook-M4-Pro.local>
This commit is contained in:
@@ -43,6 +43,7 @@ type LoginFormContentProps = {
|
||||
channels: { channel: string; icon?: string; display_name: string }[];
|
||||
handleLoginWithChannel: (channel: string) => void;
|
||||
t: ReturnType<typeof useTranslation>['t'];
|
||||
disablePasswordLogin?: boolean;
|
||||
};
|
||||
|
||||
function LoginFormContent({
|
||||
@@ -56,6 +57,7 @@ function LoginFormContent({
|
||||
channels,
|
||||
handleLoginWithChannel,
|
||||
t,
|
||||
disablePasswordLogin,
|
||||
}: LoginFormContentProps) {
|
||||
const face = useContext(FlipFaceContext);
|
||||
const isActiveFace = isLoginPage ? face === 'front' : face === 'back';
|
||||
@@ -68,6 +70,7 @@ function LoginFormContent({
|
||||
</h2>
|
||||
</div>
|
||||
<div className=" w-full max-w-[540px] bg-bg-component backdrop-blur-sm rounded-2xl shadow-xl pt-14 pl-10 pr-10 pb-2 border border-border-button ">
|
||||
{!disablePasswordLogin && (
|
||||
<Form {...form}>
|
||||
<form
|
||||
className="flex flex-col gap-8 text-text-primary "
|
||||
@@ -177,32 +180,35 @@ function LoginFormContent({
|
||||
>
|
||||
{title === 'login' ? t('login') : t('continue')}
|
||||
</ButtonLoading>
|
||||
{title === 'login' && channels && channels.length > 0 && (
|
||||
<div className="mt-3 border">
|
||||
{channels.map((item) => (
|
||||
<Button
|
||||
variant={'transparent'}
|
||||
key={item.channel}
|
||||
onClick={() => handleLoginWithChannel(item.channel)}
|
||||
style={{ marginTop: 10 }}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<SvgIcon
|
||||
name={item.icon || 'sso'}
|
||||
width={20}
|
||||
height={20}
|
||||
style={{ marginRight: 5 }}
|
||||
/>
|
||||
Sign in with {item.display_name}
|
||||
</div>
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</form>
|
||||
</Form>
|
||||
)}
|
||||
|
||||
{title === 'login' && registerEnabled && (
|
||||
{title === 'login' && channels && channels.length > 0 && (
|
||||
<div className={disablePasswordLogin ? 'py-8' : 'mt-3 border'}>
|
||||
{channels.map((item) => (
|
||||
<Button
|
||||
variant={'transparent'}
|
||||
key={item.channel}
|
||||
onClick={() => handleLoginWithChannel(item.channel)}
|
||||
style={{ marginTop: 10 }}
|
||||
className={disablePasswordLogin ? 'w-full' : ''}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<SvgIcon
|
||||
name={item.icon || 'sso'}
|
||||
width={20}
|
||||
height={20}
|
||||
style={{ marginRight: 5 }}
|
||||
/>
|
||||
Sign in with {item.display_name}
|
||||
</div>
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!disablePasswordLogin && title === 'login' && registerEnabled && (
|
||||
<div className="mt-10 text-right">
|
||||
<p className="text-text-disabled text-sm">
|
||||
{t('signInTip')}
|
||||
@@ -217,7 +223,7 @@ function LoginFormContent({
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
{title === 'register' && (
|
||||
{!disablePasswordLogin && title === 'register' && (
|
||||
<div className="mt-10 text-right">
|
||||
<p className="text-text-disabled text-sm">
|
||||
{t('signUpTip')}
|
||||
@@ -369,14 +375,8 @@ const Login = () => {
|
||||
<h1 className="text-[36px] font-medium text-center mb-2">
|
||||
{t('title')}
|
||||
</h1>
|
||||
{/* border border-accent-primary rounded-full */}
|
||||
{/* <div className="mt-4 px-6 py-1 text-sm font-medium text-cyan-600 hover:bg-cyan-50 transition-colors duration-200 border-glow relative overflow-hidden">
|
||||
{t('start')}
|
||||
</div> */}
|
||||
</div>
|
||||
<div className="relative z-10 flex flex-col items-center justify-center min-h-[1050px] px-4 sm:px-6 lg:px-8">
|
||||
{/* Logo and Header */}
|
||||
|
||||
{/* Login Form */}
|
||||
<FlipCard3D isLoginPage={isLoginPage}>
|
||||
<LoginFormContent
|
||||
@@ -390,6 +390,7 @@ const Login = () => {
|
||||
channels={channels || []}
|
||||
handleLoginWithChannel={handleLoginWithChannel}
|
||||
t={t}
|
||||
disablePasswordLogin={!!config?.disablePasswordLogin}
|
||||
/>
|
||||
</FlipCard3D>
|
||||
</div>
|
||||
@@ -398,4 +399,4 @@ const Login = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export default Login;
|
||||
export default Login;
|
||||
Reference in New Issue
Block a user