parent
a51fe1d961
commit
3a3907ab15
15 changed files with 199 additions and 384 deletions
|
@ -95,27 +95,5 @@
|
||||||
"attributeValue": "Value the attribute must have. If the attribute is a list, then the value must be contained in the list.",
|
"attributeValue": "Value the attribute must have. If the attribute is a list, then the value must be contained in the list.",
|
||||||
"attributes": "Name and (regex) value of the attributes to search for in token. The configured name of an attribute is searched in SAML attribute name and attribute friendly name fields. Every given attribute description must be met to set the role. If the attribute is an array, then the value must be contained in the array. If an attribute can be found several times, then one match is sufficient.",
|
"attributes": "Name and (regex) value of the attributes to search for in token. The configured name of an attribute is searched in SAML attribute name and attribute friendly name fields. Every given attribute description must be met to set the role. If the attribute is an array, then the value must be contained in the array. If an attribute can be found several times, then one match is sufficient.",
|
||||||
"regexAttributeValues": "If enabled attribute values are interpreted as regular expressions.",
|
"regexAttributeValues": "If enabled attribute values are interpreted as regular expressions.",
|
||||||
"role": "Role to grant to user if all attributes are present. Click 'Select Role' button to browse roles, or just type it in the textbox. To reference a client role the syntax is clientname.clientrole, i.e. myclient.myrole",
|
"role": "Role to grant to user if all attributes are present. Click 'Select Role' button to browse roles, or just type it in the textbox. To reference a client role the syntax is clientname.clientrole, i.e. myclient.myrole"
|
||||||
"baseUrl": "Override the default Base URL for this identity provider.",
|
|
||||||
"apiUrl": "Override the default API URL for this identity provider.",
|
|
||||||
"facebook": {
|
|
||||||
"fetchedFields": "Provide additional fields which would be fetched using the profile request. This will be appended to the default set of 'id,name,email,first_name,last_name'."
|
|
||||||
},
|
|
||||||
"google": {
|
|
||||||
"hostedDomain": "Set 'hd' query parameter when logging in with Google. Google will list accounts only for this domain. Keycloak validates that the returned identity token has a claim for this domain. When '*' is entered, any hosted account can be used. Comma ',' separated list of domains is supported.",
|
|
||||||
"userIp": "Set 'userIp' query parameter when invoking on Google's User Info service. This will use the user's ip address. Useful if Google is throttling access to the User Info service.",
|
|
||||||
"offlineAccess": "Set 'access_type' query parameter to 'offline' when redirecting to google authorization endpoint, to get a refresh token back. Useful if planning to use Token Exchange to retrieve Google token to access Google APIs when the user is not at the browser."
|
|
||||||
},
|
|
||||||
"openshift": {
|
|
||||||
"baseUrl": "Base Url to OpenShift Online API"
|
|
||||||
},
|
|
||||||
"paypal": {
|
|
||||||
"sandbox": "Target PayPal's sandbox environment"
|
|
||||||
},
|
|
||||||
"stackoverflow": {
|
|
||||||
"key": "The Key obtained from Stack Overflow client registration."
|
|
||||||
},
|
|
||||||
"linkedin": {
|
|
||||||
"profileProjection": "Projection parameter for profile request. Leave empty for default projection."
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,24 +178,5 @@
|
||||||
"local": "LOCAL",
|
"local": "LOCAL",
|
||||||
"brokerId": "BROKER_ID",
|
"brokerId": "BROKER_ID",
|
||||||
"brokerUsername": "BROKER_USERNAME"
|
"brokerUsername": "BROKER_USERNAME"
|
||||||
},
|
|
||||||
"baseUrl": "Base URL",
|
|
||||||
"apiUrl": "API URL",
|
|
||||||
"facebook": {
|
|
||||||
"fetchedFields": "Additional user's profile fields"
|
|
||||||
},
|
|
||||||
"google": {
|
|
||||||
"hostedDomain": "Hosted Domain",
|
|
||||||
"userIp": "Use userIp Param",
|
|
||||||
"offlineAccess": "Request refresh token"
|
|
||||||
},
|
|
||||||
"paypal": {
|
|
||||||
"sandbox": "Target Sandbox"
|
|
||||||
},
|
|
||||||
"stackoverflow": {
|
|
||||||
"key": "Key"
|
|
||||||
},
|
|
||||||
"linkedin": {
|
|
||||||
"profileProjection": "Profile Projection"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,17 +5,19 @@ import {
|
||||||
Button,
|
Button,
|
||||||
PageSection,
|
PageSection,
|
||||||
} from "@patternfly/react-core";
|
} from "@patternfly/react-core";
|
||||||
|
import { useMemo } from "react";
|
||||||
import { FormProvider, useForm } from "react-hook-form";
|
import { FormProvider, useForm } from "react-hook-form";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Link, useNavigate } from "react-router-dom";
|
import { Link, useNavigate } from "react-router-dom";
|
||||||
import { adminClient } from "../../admin-client";
|
import { adminClient } from "../../admin-client";
|
||||||
import { useAlerts } from "../../components/alert/Alerts";
|
import { useAlerts } from "../../components/alert/Alerts";
|
||||||
|
import { DynamicComponents } from "../../components/dynamic/DynamicComponents";
|
||||||
import { FormAccess } from "../../components/form/FormAccess";
|
import { FormAccess } from "../../components/form/FormAccess";
|
||||||
import { ViewHeader } from "../../components/view-header/ViewHeader";
|
import { ViewHeader } from "../../components/view-header/ViewHeader";
|
||||||
import { useRealm } from "../../context/realm-context/RealmContext";
|
import { useRealm } from "../../context/realm-context/RealmContext";
|
||||||
|
import { useServerInfo } from "../../context/server-info/ServerInfoProvider";
|
||||||
import { toUpperCase } from "../../util";
|
import { toUpperCase } from "../../util";
|
||||||
import { useParams } from "../../utils/useParams";
|
import { useParams } from "../../utils/useParams";
|
||||||
import { ExtendedFieldsForm } from "../component/ExtendedFieldsForm";
|
|
||||||
import { toIdentityProvider } from "../routes/IdentityProvider";
|
import { toIdentityProvider } from "../routes/IdentityProvider";
|
||||||
import type { IdentityProviderCreateParams } from "../routes/IdentityProviderCreate";
|
import type { IdentityProviderCreateParams } from "../routes/IdentityProviderCreate";
|
||||||
import { toIdentityProviders } from "../routes/IdentityProviders";
|
import { toIdentityProviders } from "../routes/IdentityProviders";
|
||||||
|
@ -25,6 +27,14 @@ export default function AddIdentityProvider() {
|
||||||
const { t } = useTranslation("identity-providers");
|
const { t } = useTranslation("identity-providers");
|
||||||
const { providerId } = useParams<IdentityProviderCreateParams>();
|
const { providerId } = useParams<IdentityProviderCreateParams>();
|
||||||
const form = useForm<IdentityProviderRepresentation>();
|
const form = useForm<IdentityProviderRepresentation>();
|
||||||
|
const serverInfo = useServerInfo();
|
||||||
|
const providerInfo = useMemo(
|
||||||
|
() =>
|
||||||
|
serverInfo.componentTypes?.[
|
||||||
|
"org.keycloak.broker.social.SocialIdentityProvider"
|
||||||
|
]?.find((p) => p.id === providerId),
|
||||||
|
[serverInfo, providerId]
|
||||||
|
);
|
||||||
const {
|
const {
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
formState: { isDirty },
|
formState: { isDirty },
|
||||||
|
@ -70,7 +80,9 @@ export default function AddIdentityProvider() {
|
||||||
>
|
>
|
||||||
<FormProvider {...form}>
|
<FormProvider {...form}>
|
||||||
<GeneralSettings id={providerId} />
|
<GeneralSettings id={providerId} />
|
||||||
<ExtendedFieldsForm providerId={providerId} />
|
{providerInfo && (
|
||||||
|
<DynamicComponents properties={providerInfo.properties} />
|
||||||
|
)}
|
||||||
</FormProvider>
|
</FormProvider>
|
||||||
<ActionGroup>
|
<ActionGroup>
|
||||||
<Button
|
<Button
|
||||||
|
|
|
@ -12,7 +12,7 @@ import {
|
||||||
TabTitleText,
|
TabTitleText,
|
||||||
ToolbarItem,
|
ToolbarItem,
|
||||||
} from "@patternfly/react-core";
|
} from "@patternfly/react-core";
|
||||||
import { useState } from "react";
|
import { useMemo, useState } from "react";
|
||||||
import { Controller, FormProvider, useForm } from "react-hook-form";
|
import { Controller, FormProvider, useForm } from "react-hook-form";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Link, useNavigate } from "react-router-dom";
|
import { Link, useNavigate } from "react-router-dom";
|
||||||
|
@ -20,6 +20,7 @@ import { Link, useNavigate } from "react-router-dom";
|
||||||
import { adminClient } from "../../admin-client";
|
import { adminClient } from "../../admin-client";
|
||||||
import { useAlerts } from "../../components/alert/Alerts";
|
import { useAlerts } from "../../components/alert/Alerts";
|
||||||
import { useConfirmDialog } from "../../components/confirm-dialog/ConfirmDialog";
|
import { useConfirmDialog } from "../../components/confirm-dialog/ConfirmDialog";
|
||||||
|
import { DynamicComponents } from "../../components/dynamic/DynamicComponents";
|
||||||
import { FixedButtonsGroup } from "../../components/form/FixedButtonGroup";
|
import { FixedButtonsGroup } from "../../components/form/FixedButtonGroup";
|
||||||
import { FormAccess } from "../../components/form/FormAccess";
|
import { FormAccess } from "../../components/form/FormAccess";
|
||||||
import { KeycloakSpinner } from "../../components/keycloak-spinner/KeycloakSpinner";
|
import { KeycloakSpinner } from "../../components/keycloak-spinner/KeycloakSpinner";
|
||||||
|
@ -36,11 +37,11 @@ import {
|
||||||
} from "../../components/table-toolbar/KeycloakDataTable";
|
} from "../../components/table-toolbar/KeycloakDataTable";
|
||||||
import { ViewHeader } from "../../components/view-header/ViewHeader";
|
import { ViewHeader } from "../../components/view-header/ViewHeader";
|
||||||
import { useRealm } from "../../context/realm-context/RealmContext";
|
import { useRealm } from "../../context/realm-context/RealmContext";
|
||||||
|
import { useServerInfo } from "../../context/server-info/ServerInfoProvider";
|
||||||
import { toUpperCase } from "../../util";
|
import { toUpperCase } from "../../util";
|
||||||
import { useFetch } from "../../utils/useFetch";
|
import { useFetch } from "../../utils/useFetch";
|
||||||
import useIsFeatureEnabled, { Feature } from "../../utils/useIsFeatureEnabled";
|
import useIsFeatureEnabled, { Feature } from "../../utils/useIsFeatureEnabled";
|
||||||
import { useParams } from "../../utils/useParams";
|
import { useParams } from "../../utils/useParams";
|
||||||
import { ExtendedFieldsForm } from "../component/ExtendedFieldsForm";
|
|
||||||
import { toIdentityProviderAddMapper } from "../routes/AddMapper";
|
import { toIdentityProviderAddMapper } from "../routes/AddMapper";
|
||||||
import { toIdentityProviderEditMapper } from "../routes/EditMapper";
|
import { toIdentityProviderEditMapper } from "../routes/EditMapper";
|
||||||
import {
|
import {
|
||||||
|
@ -162,6 +163,14 @@ export default function DetailSettings() {
|
||||||
const [provider, setProvider] = useState<IdentityProviderRepresentation>();
|
const [provider, setProvider] = useState<IdentityProviderRepresentation>();
|
||||||
const [selectedMapper, setSelectedMapper] =
|
const [selectedMapper, setSelectedMapper] =
|
||||||
useState<IdPWithMapperAttributes>();
|
useState<IdPWithMapperAttributes>();
|
||||||
|
const serverInfo = useServerInfo();
|
||||||
|
const providerInfo = useMemo(
|
||||||
|
() =>
|
||||||
|
serverInfo.componentTypes?.[
|
||||||
|
"org.keycloak.broker.social.SocialIdentityProvider"
|
||||||
|
]?.find((p) => p.id === providerId),
|
||||||
|
[serverInfo, providerId]
|
||||||
|
);
|
||||||
|
|
||||||
const { addAlert, addError } = useAlerts();
|
const { addAlert, addError } = useAlerts();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
@ -321,7 +330,9 @@ export default function DetailSettings() {
|
||||||
{!isOIDC && !isSAML && (
|
{!isOIDC && !isSAML && (
|
||||||
<>
|
<>
|
||||||
<GeneralSettings create={false} id={alias} />
|
<GeneralSettings create={false} id={alias} />
|
||||||
<ExtendedFieldsForm providerId={alias} />
|
{providerInfo && (
|
||||||
|
<DynamicComponents properties={providerInfo.properties} />
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{isOIDC && <OIDCGeneralSettings id={alias} />}
|
{isOIDC && <OIDCGeneralSettings id={alias} />}
|
||||||
|
|
|
@ -1,299 +0,0 @@
|
||||||
import IdentityProviderRepresentation from "@keycloak/keycloak-admin-client/lib/defs/identityProviderRepresentation";
|
|
||||||
import { FormGroup, Switch, ValidatedOptions } from "@patternfly/react-core";
|
|
||||||
import { Controller, useFormContext } from "react-hook-form";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
|
|
||||||
import { HelpItem } from "ui-shared";
|
|
||||||
import { KeycloakTextInput } from "../../components/keycloak-text-input/KeycloakTextInput";
|
|
||||||
|
|
||||||
type ExtendedFieldsFormProps = {
|
|
||||||
providerId: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const ExtendedFieldsForm = ({ providerId }: ExtendedFieldsFormProps) => {
|
|
||||||
switch (providerId) {
|
|
||||||
case "facebook":
|
|
||||||
return <FacebookFields />;
|
|
||||||
case "github":
|
|
||||||
return <GithubFields />;
|
|
||||||
case "google":
|
|
||||||
return <GoogleFields />;
|
|
||||||
case "openshift-v3":
|
|
||||||
case "openshift-v4":
|
|
||||||
return <OpenshiftFields />;
|
|
||||||
case "paypal":
|
|
||||||
return <PaypalFields />;
|
|
||||||
case "stackoverflow":
|
|
||||||
return <StackoverflowFields />;
|
|
||||||
case "linkedin":
|
|
||||||
return <LinkedInFields />;
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const FacebookFields = () => {
|
|
||||||
const { t } = useTranslation("identity-providers");
|
|
||||||
const { register } = useFormContext();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<FormGroup
|
|
||||||
label={t("facebook.fetchedFields")}
|
|
||||||
labelIcon={
|
|
||||||
<HelpItem
|
|
||||||
helpText={t("identity-providers-help:facebook:fetchedFields")}
|
|
||||||
fieldLabelId="identity-providers:facebook:fetchedFields"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
fieldId="facebookFetchedFields"
|
|
||||||
>
|
|
||||||
<KeycloakTextInput
|
|
||||||
id="facebookFetchedFields"
|
|
||||||
{...register("config.fetchedFields")}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const GithubFields = () => {
|
|
||||||
const { t } = useTranslation("identity-providers");
|
|
||||||
const { register } = useFormContext();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<FormGroup
|
|
||||||
label={t("baseUrl")}
|
|
||||||
labelIcon={
|
|
||||||
<HelpItem
|
|
||||||
helpText={t("identity-providers-help:baseUrl")}
|
|
||||||
fieldLabelId="identity-providers:baseUrl"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
fieldId="baseUrl"
|
|
||||||
>
|
|
||||||
<KeycloakTextInput
|
|
||||||
id="baseUrl"
|
|
||||||
type="url"
|
|
||||||
{...register("config.baseUrl")}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
<FormGroup
|
|
||||||
label={t("apiUrl")}
|
|
||||||
labelIcon={
|
|
||||||
<HelpItem
|
|
||||||
helpText={t("identity-providers-help:apiUrl")}
|
|
||||||
fieldLabelId="identity-providers:apiUrl"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
fieldId="apiUrl"
|
|
||||||
>
|
|
||||||
<KeycloakTextInput
|
|
||||||
id="apiUrl"
|
|
||||||
type="url"
|
|
||||||
{...register("config.apiUrl")}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const GoogleFields = () => {
|
|
||||||
const { t } = useTranslation("identity-providers");
|
|
||||||
const { register, control } = useFormContext();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<FormGroup
|
|
||||||
label={t("google.hostedDomain")}
|
|
||||||
labelIcon={
|
|
||||||
<HelpItem
|
|
||||||
helpText={t("identity-providers-help:google:hostedDomain")}
|
|
||||||
fieldLabelId="identity-providers:google:hostedDomain"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
fieldId="googleHostedDomain"
|
|
||||||
>
|
|
||||||
<KeycloakTextInput
|
|
||||||
id="googleHostedDomain"
|
|
||||||
{...register("config.hostedDomain")}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
<FormGroup
|
|
||||||
label={t("google.userIp")}
|
|
||||||
labelIcon={
|
|
||||||
<HelpItem
|
|
||||||
helpText={t("identity-providers-help:google:userIp")}
|
|
||||||
fieldLabelId="identity-providers:google:userIp"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
fieldId="googleUserIp"
|
|
||||||
>
|
|
||||||
<Controller
|
|
||||||
name="config.userIp"
|
|
||||||
defaultValue="false"
|
|
||||||
control={control}
|
|
||||||
render={({ field }) => (
|
|
||||||
<Switch
|
|
||||||
id="googleUserIp"
|
|
||||||
label={t("common:on")}
|
|
||||||
labelOff={t("common:off")}
|
|
||||||
isChecked={field.value === "true"}
|
|
||||||
onChange={(value) => field.onChange(value.toString())}
|
|
||||||
aria-label={t("google.userIp")}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
<FormGroup
|
|
||||||
label={t("google.offlineAccess")}
|
|
||||||
labelIcon={
|
|
||||||
<HelpItem
|
|
||||||
helpText={t("identity-providers-help:google:offlineAccess")}
|
|
||||||
fieldLabelId="identity-providers:google:offlineAccess"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
fieldId="googleOfflineAccess"
|
|
||||||
>
|
|
||||||
<Controller
|
|
||||||
name="config.offlineAccess"
|
|
||||||
defaultValue="false"
|
|
||||||
control={control}
|
|
||||||
render={({ field }) => (
|
|
||||||
<Switch
|
|
||||||
id="googleOfflineAccess"
|
|
||||||
label={t("common:on")}
|
|
||||||
labelOff={t("common:off")}
|
|
||||||
isChecked={field.value === "true"}
|
|
||||||
onChange={(value) => field.onChange(value.toString())}
|
|
||||||
aria-label={t("google.offlineAccess")}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const OpenshiftFields = () => {
|
|
||||||
const { t } = useTranslation("identity-providers");
|
|
||||||
const {
|
|
||||||
register,
|
|
||||||
formState: { errors },
|
|
||||||
} = useFormContext<IdentityProviderRepresentation>();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<FormGroup
|
|
||||||
label={t("baseUrl")}
|
|
||||||
labelIcon={
|
|
||||||
<HelpItem
|
|
||||||
helpText={t("identity-providers-help:openshift:baseUrl")}
|
|
||||||
fieldLabelId="identity-providers:baseUrl"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
fieldId="baseUrl"
|
|
||||||
isRequired
|
|
||||||
validated={
|
|
||||||
errors.config?.baseUrl
|
|
||||||
? ValidatedOptions.error
|
|
||||||
: ValidatedOptions.default
|
|
||||||
}
|
|
||||||
helperTextInvalid={t("common:required")}
|
|
||||||
>
|
|
||||||
<KeycloakTextInput
|
|
||||||
id="baseUrl"
|
|
||||||
type="url"
|
|
||||||
isRequired
|
|
||||||
{...register("config.baseUrl", { required: true })}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const PaypalFields = () => {
|
|
||||||
const { t } = useTranslation("identity-providers");
|
|
||||||
const { control } = useFormContext();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<FormGroup
|
|
||||||
label={t("paypal.sandbox")}
|
|
||||||
labelIcon={
|
|
||||||
<HelpItem
|
|
||||||
helpText={t("identity-providers-help:paypal:sandbox")}
|
|
||||||
fieldLabelId="identity-providers:paypal:sandbox"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
fieldId="paypalSandbox"
|
|
||||||
>
|
|
||||||
<Controller
|
|
||||||
name="config.sandbox"
|
|
||||||
defaultValue="false"
|
|
||||||
control={control}
|
|
||||||
render={({ field }) => (
|
|
||||||
<Switch
|
|
||||||
id="paypalSandbox"
|
|
||||||
label={t("common:on")}
|
|
||||||
labelOff={t("common:off")}
|
|
||||||
isChecked={field.value === "true"}
|
|
||||||
onChange={(value) => field.onChange(value.toString())}
|
|
||||||
aria-label={t("paypal.sandbox")}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const StackoverflowFields = () => {
|
|
||||||
const { t } = useTranslation("identity-providers");
|
|
||||||
const {
|
|
||||||
register,
|
|
||||||
formState: { errors },
|
|
||||||
} = useFormContext<IdentityProviderRepresentation>();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<FormGroup
|
|
||||||
label={t("stackoverflow.key")}
|
|
||||||
labelIcon={
|
|
||||||
<HelpItem
|
|
||||||
helpText={t("identity-providers-help:stackoverflow:key")}
|
|
||||||
fieldLabelId="identity-providers:stackoverflow:key"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
fieldId="stackoverflowKey"
|
|
||||||
isRequired
|
|
||||||
validated={
|
|
||||||
errors.config?.key ? ValidatedOptions.error : ValidatedOptions.default
|
|
||||||
}
|
|
||||||
helperTextInvalid={t("common:required")}
|
|
||||||
>
|
|
||||||
<KeycloakTextInput
|
|
||||||
id="stackoverflowKey"
|
|
||||||
isRequired
|
|
||||||
{...register("config.key", { required: true })}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const LinkedInFields = () => {
|
|
||||||
const { t } = useTranslation("identity-providers");
|
|
||||||
const { register } = useFormContext();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<FormGroup
|
|
||||||
label={t("linkedin.profileProjection")}
|
|
||||||
labelIcon={
|
|
||||||
<HelpItem
|
|
||||||
helpText={t("identity-providers-help:linkedin.profileProjection")}
|
|
||||||
fieldLabelId="identity-providers:linkedin.profileProjection"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
fieldId="profileProjection"
|
|
||||||
>
|
|
||||||
<KeycloakTextInput
|
|
||||||
id="profileProjection"
|
|
||||||
{...register("config.profileProjection")}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
);
|
|
||||||
};
|
|
|
@ -18,15 +18,19 @@ package org.keycloak.broker.provider;
|
||||||
|
|
||||||
import org.keycloak.models.IdentityProviderModel;
|
import org.keycloak.models.IdentityProviderModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.provider.ConfiguredProvider;
|
||||||
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
import org.keycloak.provider.ProviderFactory;
|
import org.keycloak.provider.ProviderFactory;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Pedro Igor
|
* @author Pedro Igor
|
||||||
*/
|
*/
|
||||||
public interface IdentityProviderFactory<T extends IdentityProvider> extends ProviderFactory<T> {
|
public interface IdentityProviderFactory<T extends IdentityProvider> extends ProviderFactory<T>, ConfiguredProvider {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>A friendly name for this factory.</p>
|
* <p>A friendly name for this factory.</p>
|
||||||
|
@ -64,4 +68,10 @@ public interface IdentityProviderFactory<T extends IdentityProvider> extends Pro
|
||||||
* @return the provider specific instance
|
* @return the provider specific instance
|
||||||
*/
|
*/
|
||||||
IdentityProviderModel createConfig();
|
IdentityProviderModel createConfig();
|
||||||
|
|
||||||
|
default List<ProviderConfigProperty> getConfigProperties() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
default String getHelpText() { return ""; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,10 @@ import org.keycloak.broker.provider.AbstractIdentityProviderFactory;
|
||||||
import org.keycloak.broker.social.SocialIdentityProviderFactory;
|
import org.keycloak.broker.social.SocialIdentityProviderFactory;
|
||||||
import org.keycloak.models.IdentityProviderModel;
|
import org.keycloak.models.IdentityProviderModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
|
import org.keycloak.provider.ProviderConfigurationBuilder;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Pedro Igor
|
* @author Pedro Igor
|
||||||
|
@ -48,4 +52,14 @@ public class FacebookIdentityProviderFactory extends AbstractIdentityProviderFac
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return PROVIDER_ID;
|
return PROVIDER_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ProviderConfigProperty> getConfigProperties() {
|
||||||
|
return ProviderConfigurationBuilder.create()
|
||||||
|
.property().name("fetchedFields")
|
||||||
|
.label("Additional user's profile fields")
|
||||||
|
.helpText("Provide additional fields which would be fetched using the profile request. This will be appended to the default set of 'id,name,email,first_name,last_name'.")
|
||||||
|
.type(ProviderConfigProperty.STRING_TYPE)
|
||||||
|
.add().build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,10 @@ import org.keycloak.broker.provider.AbstractIdentityProviderFactory;
|
||||||
import org.keycloak.models.IdentityProviderModel;
|
import org.keycloak.models.IdentityProviderModel;
|
||||||
import org.keycloak.broker.social.SocialIdentityProviderFactory;
|
import org.keycloak.broker.social.SocialIdentityProviderFactory;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
|
import org.keycloak.provider.ProviderConfigurationBuilder;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Pedro Igor
|
* @author Pedro Igor
|
||||||
|
@ -48,4 +52,13 @@ public class GitHubIdentityProviderFactory extends AbstractIdentityProviderFacto
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return PROVIDER_ID;
|
return PROVIDER_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ProviderConfigProperty> getConfigProperties() {
|
||||||
|
return ProviderConfigurationBuilder.create().property()
|
||||||
|
.name("baseUrl").label("Base URL").helpText("Override the default Base URL for this identity provider.")
|
||||||
|
.type(ProviderConfigProperty.STRING_TYPE).add().property()
|
||||||
|
.name("apiUrl").label("API URL").helpText("Override the default API URL for this identity provider.")
|
||||||
|
.type(ProviderConfigProperty.STRING_TYPE).add().build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,10 @@ import org.keycloak.broker.provider.AbstractIdentityProviderFactory;
|
||||||
import org.keycloak.models.IdentityProviderModel;
|
import org.keycloak.models.IdentityProviderModel;
|
||||||
import org.keycloak.broker.social.SocialIdentityProviderFactory;
|
import org.keycloak.broker.social.SocialIdentityProviderFactory;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
|
import org.keycloak.provider.ProviderConfigurationBuilder;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Pedro Igor
|
* @author Pedro Igor
|
||||||
|
@ -47,4 +51,27 @@ public class GoogleIdentityProviderFactory extends AbstractIdentityProviderFacto
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return PROVIDER_ID;
|
return PROVIDER_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ProviderConfigProperty> getConfigProperties() {
|
||||||
|
return ProviderConfigurationBuilder.create()
|
||||||
|
.property().name("hostedDomain")
|
||||||
|
.label("Hosted Domain")
|
||||||
|
.helpText("Set 'hd' query parameter when logging in with Google. Google will list accounts only for this " +
|
||||||
|
"domain. Keycloak validates that the returned identity token has a claim for this domain. When '*' " +
|
||||||
|
"is entered, any hosted account can be used. Comma ',' separated list of domains is supported.")
|
||||||
|
.type(ProviderConfigProperty.STRING_TYPE).add()
|
||||||
|
.property().name("userIp")
|
||||||
|
.label("Use userIp param")
|
||||||
|
.helpText("Set 'userIp' query parameter when invoking on Google's User Info service. This will use the " +
|
||||||
|
"user's ip address. Useful if Google is throttling access to the User Info service.")
|
||||||
|
.type(ProviderConfigProperty.BOOLEAN_TYPE).add()
|
||||||
|
.property().name("offlineAccess")
|
||||||
|
.label("Request refresh token")
|
||||||
|
.helpText("Set 'access_type' query parameter to 'offline' when redirecting to google authorization " +
|
||||||
|
"endpoint, to get a refresh token back. Useful if planning to use Token Exchange to retrieve " +
|
||||||
|
"Google token to access Google APIs when the user is not at the browser.")
|
||||||
|
.type(ProviderConfigProperty.BOOLEAN_TYPE)
|
||||||
|
.add().build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,32 +21,45 @@ import org.keycloak.broker.provider.AbstractIdentityProviderFactory;
|
||||||
import org.keycloak.models.IdentityProviderModel;
|
import org.keycloak.models.IdentityProviderModel;
|
||||||
import org.keycloak.broker.social.SocialIdentityProviderFactory;
|
import org.keycloak.broker.social.SocialIdentityProviderFactory;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
|
import org.keycloak.provider.ProviderConfigurationBuilder;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Vlastimil Elias (velias at redhat dot com)
|
* @author Vlastimil Elias (velias at redhat dot com)
|
||||||
*/
|
*/
|
||||||
public class LinkedInIdentityProviderFactory extends AbstractIdentityProviderFactory<LinkedInIdentityProvider>
|
public class LinkedInIdentityProviderFactory extends AbstractIdentityProviderFactory<LinkedInIdentityProvider>
|
||||||
implements SocialIdentityProviderFactory<LinkedInIdentityProvider> {
|
implements SocialIdentityProviderFactory<LinkedInIdentityProvider> {
|
||||||
|
|
||||||
public static final String PROVIDER_ID = "linkedin";
|
public static final String PROVIDER_ID = "linkedin";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "LinkedIn";
|
return "LinkedIn";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LinkedInIdentityProvider create(KeycloakSession session, IdentityProviderModel model) {
|
public LinkedInIdentityProvider create(KeycloakSession session, IdentityProviderModel model) {
|
||||||
return new LinkedInIdentityProvider(session, new OAuth2IdentityProviderConfig(model));
|
return new LinkedInIdentityProvider(session, new OAuth2IdentityProviderConfig(model));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OAuth2IdentityProviderConfig createConfig() {
|
public OAuth2IdentityProviderConfig createConfig() {
|
||||||
return new OAuth2IdentityProviderConfig();
|
return new OAuth2IdentityProviderConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return PROVIDER_ID;
|
return PROVIDER_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ProviderConfigProperty> getConfigProperties() {
|
||||||
|
return ProviderConfigurationBuilder.create()
|
||||||
|
.property().name("profileProjection")
|
||||||
|
.label("Profile projection")
|
||||||
|
.helpText("Projection parameter for profile request. Leave empty for default projection.")
|
||||||
|
.add().build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,9 @@ import org.keycloak.broker.provider.AbstractIdentityProviderFactory;
|
||||||
import org.keycloak.broker.social.SocialIdentityProviderFactory;
|
import org.keycloak.broker.social.SocialIdentityProviderFactory;
|
||||||
import org.keycloak.models.IdentityProviderModel;
|
import org.keycloak.models.IdentityProviderModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class OpenshiftV3IdentityProviderFactory extends AbstractIdentityProviderFactory<OpenshiftV3IdentityProvider> implements SocialIdentityProviderFactory<OpenshiftV3IdentityProvider> {
|
public class OpenshiftV3IdentityProviderFactory extends AbstractIdentityProviderFactory<OpenshiftV3IdentityProvider> implements SocialIdentityProviderFactory<OpenshiftV3IdentityProvider> {
|
||||||
|
|
||||||
|
@ -29,4 +32,8 @@ public class OpenshiftV3IdentityProviderFactory extends AbstractIdentityProvider
|
||||||
return PROVIDER_ID;
|
return PROVIDER_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ProviderConfigProperty> getConfigProperties() {
|
||||||
|
return OpenshiftV4IdentityProviderConfig.getConfigProperties();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,10 @@ package org.keycloak.social.openshift;
|
||||||
|
|
||||||
import org.keycloak.broker.oidc.OAuth2IdentityProviderConfig;
|
import org.keycloak.broker.oidc.OAuth2IdentityProviderConfig;
|
||||||
import org.keycloak.models.IdentityProviderModel;
|
import org.keycloak.models.IdentityProviderModel;
|
||||||
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
|
import org.keycloak.provider.ProviderConfigurationBuilder;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@ -36,4 +39,13 @@ public class OpenshiftV4IdentityProviderConfig extends OAuth2IdentityProviderCon
|
||||||
public void setBaseUrl(String baseUrl) {
|
public void setBaseUrl(String baseUrl) {
|
||||||
getConfig().put(BASE_URL, trimTrailingSlash(baseUrl));
|
getConfig().put(BASE_URL, trimTrailingSlash(baseUrl));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<ProviderConfigProperty> getConfigProperties() {
|
||||||
|
return ProviderConfigurationBuilder.create()
|
||||||
|
.property().name(BASE_URL)
|
||||||
|
.label("Base URL")
|
||||||
|
.helpText("Override the default Base URL for this identity provider.")
|
||||||
|
.type(ProviderConfigProperty.STRING_TYPE)
|
||||||
|
.add().build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,9 @@ import org.keycloak.broker.provider.AbstractIdentityProviderFactory;
|
||||||
import org.keycloak.broker.social.SocialIdentityProviderFactory;
|
import org.keycloak.broker.social.SocialIdentityProviderFactory;
|
||||||
import org.keycloak.models.IdentityProviderModel;
|
import org.keycloak.models.IdentityProviderModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* OpenShift 4 Identity Provider factory class.
|
* OpenShift 4 Identity Provider factory class.
|
||||||
|
@ -34,4 +37,9 @@ public class OpenshiftV4IdentityProviderFactory extends AbstractIdentityProvider
|
||||||
public OpenshiftV4IdentityProviderConfig createConfig() {
|
public OpenshiftV4IdentityProviderConfig createConfig() {
|
||||||
return new OpenshiftV4IdentityProviderConfig();
|
return new OpenshiftV4IdentityProviderConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ProviderConfigProperty> getConfigProperties() {
|
||||||
|
return OpenshiftV4IdentityProviderConfig.getConfigProperties();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,10 @@ import org.keycloak.broker.provider.AbstractIdentityProviderFactory;
|
||||||
import org.keycloak.models.IdentityProviderModel;
|
import org.keycloak.models.IdentityProviderModel;
|
||||||
import org.keycloak.broker.social.SocialIdentityProviderFactory;
|
import org.keycloak.broker.social.SocialIdentityProviderFactory;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
|
import org.keycloak.provider.ProviderConfigurationBuilder;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Petter Lysne
|
* @author Petter Lysne
|
||||||
|
@ -48,4 +52,14 @@ public class PayPalIdentityProviderFactory extends AbstractIdentityProviderFacto
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return PROVIDER_ID;
|
return PROVIDER_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ProviderConfigProperty> getConfigProperties() {
|
||||||
|
return ProviderConfigurationBuilder.create()
|
||||||
|
.property().name("sandbox")
|
||||||
|
.type(ProviderConfigProperty.BOOLEAN_TYPE)
|
||||||
|
.label("Target Sandbox")
|
||||||
|
.helpText("Target PayPal's sandbox environment")
|
||||||
|
.add().build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,33 +20,47 @@ import org.keycloak.broker.provider.AbstractIdentityProviderFactory;
|
||||||
import org.keycloak.models.IdentityProviderModel;
|
import org.keycloak.models.IdentityProviderModel;
|
||||||
import org.keycloak.broker.social.SocialIdentityProviderFactory;
|
import org.keycloak.broker.social.SocialIdentityProviderFactory;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
|
import org.keycloak.provider.ProviderConfigurationBuilder;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Vlastimil Elias (velias at redhat dot com)
|
* @author Vlastimil Elias (velias at redhat dot com)
|
||||||
*/
|
*/
|
||||||
public class StackoverflowIdentityProviderFactory extends
|
public class StackoverflowIdentityProviderFactory extends
|
||||||
AbstractIdentityProviderFactory<StackoverflowIdentityProvider> implements
|
AbstractIdentityProviderFactory<StackoverflowIdentityProvider> implements
|
||||||
SocialIdentityProviderFactory<StackoverflowIdentityProvider> {
|
SocialIdentityProviderFactory<StackoverflowIdentityProvider> {
|
||||||
|
|
||||||
public static final String PROVIDER_ID = "stackoverflow";
|
public static final String PROVIDER_ID = "stackoverflow";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "StackOverflow";
|
return "StackOverflow";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StackoverflowIdentityProvider create(KeycloakSession session, IdentityProviderModel model) {
|
public StackoverflowIdentityProvider create(KeycloakSession session, IdentityProviderModel model) {
|
||||||
return new StackoverflowIdentityProvider(session, new StackOverflowIdentityProviderConfig(model));
|
return new StackoverflowIdentityProvider(session, new StackOverflowIdentityProviderConfig(model));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StackOverflowIdentityProviderConfig createConfig() {
|
public StackOverflowIdentityProviderConfig createConfig() {
|
||||||
return new StackOverflowIdentityProviderConfig();
|
return new StackOverflowIdentityProviderConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return PROVIDER_ID;
|
return PROVIDER_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ProviderConfigProperty> getConfigProperties() {
|
||||||
|
return ProviderConfigurationBuilder.create()
|
||||||
|
.property().name("key")
|
||||||
|
.type(ProviderConfigProperty.STRING_TYPE)
|
||||||
|
.label("Key")
|
||||||
|
.helpText("The Key obtained from Stack Overflow client registration.")
|
||||||
|
.add().build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue