diff --git a/server_development/topics/action-token-spi.adoc b/server_development/topics/action-token-spi.adoc index ec5be17763..04fe065ec9 100644 --- a/server_development/topics/action-token-spi.adoc +++ b/server_development/topics/action-token-spi.adoc @@ -16,7 +16,7 @@ In addition to that, it is possible to implement any functionality that initiate using action token SPI, details of which are described in the text below. [[_action_token_anatomy]] -=== Anatomy of Action Token +=== Anatomy of action token Action token is a standard Json Web Token signed with active realm key where the payload contains several fields: @@ -31,7 +31,7 @@ Action token is a standard Json Web Token signed with active realm key where the In addition, an action token can contain any number of custom fields serializable into JSON. -=== Action Token Processing +=== Action token processing When an action token is passed to a {project_name} endpoint `_KEYCLOAK_ROOT_/auth/realms/master/login-actions/action-token` via `key` parameter, it is validated and a proper action @@ -60,9 +60,9 @@ action according to parameters in the token. 5. *Invalidation of single-Use tokens.* If the token is set to single-use, once the authentication flow finishes, the action token is invalidated. -=== Implement Your Own Action Token and its Handler +=== Implement your own action token and its handler -==== How to Create an Action Token +==== How to create an action token As action token is just a signed JWT with few mandatory fields (see <<_action_token_anatomy,Anatomy of action token>> above), it can be serialized and signed as such using Keycloak's `JWSBuilder` class. This way has been already @@ -131,7 +131,7 @@ public class DemoActionToken extends DefaultActionToken { ---- -==== Packaging Classes and Deployment +==== Packaging classes and deployment To plug your own action token and its handler, you need to implement few interfaces on server side: diff --git a/server_development/topics/admin-rest-api.adoc b/server_development/topics/admin-rest-api.adoc index 7a46a13971..683a70ef6d 100644 --- a/server_development/topics/admin-rest-api.adoc +++ b/server_development/topics/admin-rest-api.adoc @@ -2,19 +2,24 @@ {project_name} comes with a fully functional Admin REST API with all features provided by the Admin Console. -To invoke the API you need to obtain an access token with the appropriate permissions. The required permissions are described in -{adminguide_link}[{adminguide_name}]. +To invoke the API you need to obtain an access token with the appropriate permissions. The required permissions are described in the Server Administration Guide. -A token can be obtained by enabling authenticating to your application with {project_name}; see the -{adapterguide_link}[{adapterguide_name}]. You can also use direct access grant to obtain an access token. +A token can be obtained by enabling authenticating to your application with {project_name}; see the Securing Applications and Services Guide. You can also use direct access grant to obtain an access token. -For complete documentation see {apidocs_link}[{apidocs_name}]. +.Additional resources +[role="_additional-resources"] +* {adminguide_link}[{adminguide_name}] +* {adapterguide_link}[{adapterguide_name}] +* {apidocs_link}[{apidocs_name}] -=== Examples using CURL +=== Examples of using CURL ==== Authenticate with username and password -Obtain access token for user in the realm `master` with username `admin` and password `password`: +.Procedure + +. Obtain an access token for user in the realm `master` with username `admin` and password `password`: ++ [source,bash] ---- curl \ @@ -24,14 +29,17 @@ curl \ -d "grant_type=password" \ "http://localhost:8080/auth/realms/master/protocol/openid-connect/token" ---- - ++ NOTE: By default this token expires in 1 minute ++ +The result will be a JSON document. -The result will be a JSON document. To invoke the API you need to extract the value of the `access_token` property. You can then invoke the API by including -the value in the `Authorization` header of requests to the API. +. Invoke the API you need by extracting the value of the `access_token` property. +. Invoke the API by including the value in the `Authorization` header of requests to the API. ++ The following example shows how to get the details of the master realm: - ++ [source,bash] ---- curl \ @@ -71,6 +79,7 @@ The following example shows how to use the Java client library to get the detail [source,java] ---- + import org.keycloak.admin.client.Keycloak; import org.keycloak.representations.idm.RealmRepresentation; ... @@ -86,3 +95,4 @@ RealmRepresentation realm = keycloak.realm("master").toRepresentation(); Complete Javadoc for the admin client is available at {apidocs_link}[{apidocs_name}]. endif::[] + diff --git a/server_development/topics/auth-spi.adoc b/server_development/topics/auth-spi.adoc index abb33e6475..d20cbacfc8 100644 --- a/server_development/topics/auth-spi.adoc +++ b/server_development/topics/auth-spi.adoc @@ -4,10 +4,10 @@ {project_name} includes a range of different authentication mechanisms: kerberos, password, otp and others. These mechanisms may not meet all of your requirements and you may want to plug in your own custom ones. {project_name} provides an authentication SPI that you can use to write new plugins. -The admin console supports applying, ordering, and configuring these new mechanisms. +The Admin Console supports applying, ordering, and configuring these new mechanisms. {project_name} also supports a simple registration form. -Different aspects of this form can be enabled and disabled i.e. +Different aspects of this form can be enabled and disabled for example Recaptcha support can be turned off and on. The same authentication SPI can be used to add another page to the registration flow or reimplement it entirely. There's also an additional fine-grained SPI you can use to add specific validations and user extensions to the built in registration form. @@ -26,7 +26,7 @@ To first learn about the Authentication SPI, let's go over some of the terms use Authentication Flow:: A flow is a container for all authentications that must happen during login or registration. - If you go to the admin console authentication page, you can view all the defined flows in the system and what authenticators they are made up of. + If you go to the Admin Console authentication page, you can view all the defined flows in the system and what authenticators they are made up of. Flows can contain other flows. You can also bind a new different flow for browser login, direct grant access, and registration. @@ -54,7 +54,7 @@ Required Action:: After authentication completes, the user might have one or more one-time actions he must complete before he is allowed to login. The user might be required to set up an OTP token generator or reset an expired password or even accept a Terms and Conditions document. -=== Algorithm Overview +=== Algorithm overview Let's talk about how this all works for browser login. Let's assume the following flows, executions and sub flows. @@ -146,7 +146,7 @@ Let's walk through the steps from when a client first redirects to keycloak to a . After all required actions have been resolved, the user is finally logged in. [[_auth_spi_walkthrough]] -=== Authenticator SPI Walk Through +=== Authenticator SPI walk through In this section, we'll take a look at the Authenticator interface. For this, we are going to implement an authenticator that requires that a user enter in the answer to a secret question like "What is your mother's maiden name?". @@ -169,7 +169,7 @@ These types of authenticators are called CredentialValidators, and will require The SecretQuestionAuthenticator we'll see in this walk through is a CredentialValidator, so we'll see how to implement all these classes. -==== Packaging Classes and Deployment +==== Packaging classes and deployment You will package your classes within a single jar. This jar must contain a file named `org.keycloak.authentication.AuthenticatorFactory` and must be contained in the `META-INF/services/` directory of your jar. @@ -218,7 +218,7 @@ Where: * `created_date` is the creation timestamp (in long format) of the credential. * `user_label` is the editable name of the credential by the user * `secret_data` contains a static json with the information that cannot be transmitted outside of {project_name} -* `credential_data` contains a json with the static information of the credential that can be shared in the admin console or via the REST API. +* `credential_data` contains a json with the static information of the credential that can be shared in the Admin Console or via the REST API. * `priority` defines how "preferred" a credential is for a user, to determine which credential to present when a user has multiple choices. As the secret_data and credential_data fields are designed to contain json, it is up to you to determine how to structure, read and write into @@ -479,7 +479,7 @@ public boolean isConfiguredFor(RealmModel realm, UserModel user, String credenti } ---- -==== Implementing an Authenticator +==== Implementing an authenticator When implementing an authenticator that uses Credentials to authenticate a user, you should have the authenticator implement the CredentialValidator interface. This interfaces takes a class extending a CredentialProvider as a parameter, and will @@ -644,7 +644,7 @@ protected void setCookie(AuthenticationFlowContext context) { We obtain an AuthenticatorConfigModel from the AuthenticationFlowContext.getAuthenticatorConfig() method. If configuration exists we pull the max age config out of it. We will see how we can define what should be configured when we talk about the AuthenticatorFactory implementation. -The config values can be defined within the admin console if you set up config definitions in your AuthenticatorFactory implementation. +The config values can be defined within the Admin Console if you set up config definitions in your AuthenticatorFactory implementation. [source,java] ---- @@ -699,7 +699,7 @@ public class SecretQuestionAuthenticatorFactory implements AuthenticatorFactory, The next thing the factory is responsible for is to specify the allowed requirement switches. While there are four different requirement types: ALTERNATIVE, REQUIRED, CONDITIONAL, DISABLED, AuthenticatorFactory implementations can limit which -requirement options are shown in the admin console when defining a flow. CONDITIONAL should only always be used for subflows, and unless there's a good +requirement options are shown in the Admin Console when defining a flow. CONDITIONAL should only always be used for subflows, and unless there's a good reason for doing otherwise, the requirement on a authenticator should be REQUIRED, ALTERNATIVE and DISABLED: [source,java] @@ -730,7 +730,7 @@ If it returns true, then the flow manager will invoke Authenticator.setRequiredA ---- The next few methods define how the Authenticator can be configured. -The isConfigurable() method is a flag which specifies to the admin console on whether the Authenticator can be configured within a flow. +The isConfigurable() method is a flag which specifies to the Admin Console on whether the Authenticator can be configured within a flow. The getConfigProperties() method returns a list of ProviderConfigProperty objects. These objects define a specific configuration attribute. @@ -757,18 +757,18 @@ These objects define a specific configuration attribute. Each ProviderConfigProperty defines the name of the config property. This is the key used in the config map stored in AuthenticatorConfigModel. -The label defines how the config option will be displayed in the admin console. +The label defines how the config option will be displayed in the Admin Console. The type defines if it is a String, Boolean, or other type. -The admin console will display different UI inputs depending on the type. -The help text is what will be shown in the tooltip for the config attribute in the admin console. +The Admin Console will display different UI inputs depending on the type. +The help text is what will be shown in the tooltip for the config attribute in the Admin Console. Read the javadoc of ProviderConfigProperty for more detail. -The rest of the methods are for the admin console. +The rest of the methods are for the Admin Console. getHelpText() is the tooltip text that will be shown when you are picking the Authenticator you want to bind to an execution. -getDisplayType() is the text that will be shown in the admin console when listing the Authenticator. +getDisplayType() is the text that will be shown in the Admin Console when listing the Authenticator. getReferenceCategory() is just a category the Authenticator belongs to. -==== Adding Authenticator Form +==== Adding an authenticator form {project_name} comes with a Freemarker <<_themes,theme and template engine>>. The createForm() method you called within authenticate() of your Authenticator class, builds an HTML page from a file within your login theme: `secret-question.ftl`. @@ -818,9 +818,9 @@ Importing this template, instead of the standard `template.ftl` allows {project_ a different credential or execution. [[_adding_authenticator]] -==== Adding Authenticator to a Flow +==== Adding an authenticator to a flow -Adding an Authenticator to a flow must be done in the admin console. +Adding an Authenticator to a flow must be done in the Admin Console. If you go to the Authentication menu item and go to the Flow tab, you will be able to view the currently defined flows. You cannot modify built in flows, so, to add the Authenticator we've created you have to copy an existing flow or create your own. Our hope is that the user interface is sufficiently clear so that you can determine how to create a flow and add the Authenticator. For @@ -829,13 +829,13 @@ more details, see the `Authentication Flows` chapter in link:{adminguide_link}[{ After you've created your flow, you have to bind it to the login action you want to bind it to. If you go to the Authentication menu and go to the Bindings tab you will see options to bind a flow to the browser, registration, or direct grant flow. -=== Required Action Walkthrough +=== Required action walkthrough In this section we will discuss how to define a required action. In the Authenticator section you may have wondered, "How will we get the user's answer to the secret question entered into the system?". As we showed in the example, if the answer is not set up, a required action will be triggered. This section discusses how to implement the required action for the Secret Question Authenticator. -==== Packaging Classes and Deployment +==== Packaging classes and deployment You will package your classes within a single jar. This jar does not have to be separate from other provider classes but it must contain a file named `org.keycloak.authentication.RequiredActionFactory` and must be contained in the `META-INF/services/` directory of your jar. @@ -927,17 +927,17 @@ public class SecretQuestionRequiredActionFactory implements RequiredActionFactor } ---- -The getDisplayText() method is just for the admin console when it wants to display a friendly name for the required action. +The getDisplayText() method is just for the Admin Console when it wants to display a friendly name for the required action. -==== Enable Required Action +==== Enable required action -The final thing you have to do is go into the admin console. +The final thing you have to do is go into the Admin Console. Click on the Authentication left menu. Click on the Required Actions tab. Click on the Register button and choose your new Required Action. Your new required action should now be displayed and enabled in the required actions list. -=== Modifying/Extending the Registration Form +=== Modifying or extending the registration form It is entirely possible for you to implement your own flow with a set of Authenticators to totally change how registration is done in {project_name}. But what you'll usually want to do is just add a little bit of validation to the out of the box registration page. @@ -945,7 +945,7 @@ An additional SPI was created to be able to do this. It basically allows you to add validation of form elements on the page as well as to initialize UserModel attributes and data after the user has been registered. We'll look at both the implementation of the user profile registration processing as well as the registration Google Recaptcha plugin. -==== Implementation FormAction Interface +==== Implementation FormAction interface The core interface you have to implement is the FormAction interface. A FormAction is responsible for rendering and processing a portion of the page. @@ -1025,8 +1025,7 @@ We then validate the recaptcha. If successful, ValidationContext.success() is called. If not, we invoke ValidationContext.validationError() passing in the formData (so the user doesn't have to re-enter data), we also specify an error message we want displayed. The error message must point to a message bundle property in the internationalized message bundles. -For other registration extensions validate() might be validating the format of a form element, i.e. -an alternative email attribute. +For other registration extensions validate() might be validating the format of a form element, for example an alternative email attribute. Let's also look at the user profile plugin that is used to validate email address and other user information when registering. @@ -1106,7 +1105,7 @@ The appropriate methods are called to initialize UserModel data. Finally, you are also required to define a FormActionFactory class. This class is implemented similarly to AuthenticatorFactory, so we won't go over it. -==== Packaging the Action +==== Packaging the action You will package your classes within a single jar. This jar must contain a file named `org.keycloak.authentication.FormActionFactory` and must be contained in the `META-INF/services/` directory of your jar. @@ -1124,9 +1123,9 @@ This services/ file is used by {project_name} to scan the providers it has to lo To deploy this jar, just copy it to the `standalone/deployments` directory. -==== Adding FormAction to the Registration Flow +==== Adding FormAction to the registration flow -Adding a FormAction to a registration page flow must be done in the admin console. +Adding a FormAction to a registration page flow must be done in the Admin Console. If you go to the Authentication menu item and go to the Flow tab, you will be able to view the currently defined flows. You cannot modify built in flows, so, to add the Authenticator we've created you have to copy an existing flow or create your own. I'm hoping the UI is intuitive enough so that you can figure out for yourself how to create a flow and add the FormAction. @@ -1139,10 +1138,10 @@ Make sure your FormAction comes after "Registration User Creation" by using the After you've created your flow, you have to bind it to registration. If you go to the Authentication menu and go to the Bindings tab you will see options to bind a flow to the browser, registration, or direct grant flow. -=== Modifying Forgot Password/Credential Flow +=== Modifying forgot password/credential flow {project_name} also has a specific authentication flow for forgot password, or rather credential reset initiated by a user. -If you go to the admin console flows page, there is a "reset credentials" flow. +If you go to the Admin Console flows page, there is a "reset credentials" flow. By default, {project_name} asks for the email or username of the user and sends an email to them. If the user clicks on the link, then they are able to reset both their password and OTP (if an OTP has been set up). You can disable automatic OTP reset by disabling the "Reset OTP" authenticator in the flow. @@ -1160,11 +1159,14 @@ So, if AuthenticationFlowContext.getUser() returns null, you should proceed with I suggest that if you want to add secret questions to this flow, you should ask these questions after the email is sent. In other words, add your custom authenticator after the "Send Reset Email" authenticator. -=== Modifying First Broker Login Flow +=== Modifying first broker login flow First Broker Login flow is used during first login with some identity provider. Term `First Login` means that there is not yet existing {project_name} account linked with the particular authenticated identity provider account. -For more details about this flow see the `Identity Brokering` chapter in link:{adminguide_link}[{adminguide_name}] . + +[role="_additional-resource"] +.Additional resources +* See the `Identity Brokering` chapter in link:{adminguide_link}[{adminguide_name}] . [[_client_authentication]] === Authentication of clients @@ -1175,7 +1177,9 @@ to the {project_name} server (like the request for exchange code to access token But the client authentication can be also used directly by you during `Direct Access grants` (represented by OAuth2 `Resource Owner Password Credentials Flow`) or during `Service account` authentication (represented by OAuth2 `Client Credentials Flow`). -For more details about {project_name} adapter and OAuth2 flows see link:{adapterguide_link}[{adapterguide_name}]. +[role="_additional-resource"] +.Additional resources +* For more details about {project_name} adapter and OAuth2 flows see link:{adapterguide_link}[{adapterguide_name}]. ==== Default implementations diff --git a/server_development/topics/custom-attributes.adoc b/server_development/topics/custom-attributes.adoc index cc1a029d32..36dcc68722 100644 --- a/server_development/topics/custom-attributes.adoc +++ b/server_development/topics/custom-attributes.adoc @@ -1,16 +1,25 @@ [[_custom_user_attributes]] -== Custom User Attributes +== Custom user attributes -You can add custom user attributes to the registration page and account management console with a custom theme. This chapter describes how to add attributes -to a custom theme, but you should refer to the <<_themes,Themes>> chapter on how to create a custom theme. +You can add custom user attributes to the registration page and account management console with a custom theme. -=== Registration Page +[role="_additional-resources"] +.Additional resources -To be able to enter custom attributes in the registration page copy the template `themes/base/login/register.ftl` to the login type of your custom theme. Then -open the copy in an editor. +* See <<_themes,Themes>> for how to create a custom theme. -As an example to add a mobile number to the registration page add the following snippet to the form: +=== Registration page +Use this procedure to enter custom attributes in the registration page. + +.Procedure + +. copy the template `themes/base/login/register.ftl` to the login type of your custom theme. + +. open the copy in an editor. ++ +For example, to add a mobile number to the registration page, add the following snippet to the form: ++ [source,html] ----
@@ -24,17 +33,22 @@ As an example to add a mobile number to the registration page add the following
---- -Ensure the name of the input html element starts with `user.attributes.`. In the example above, the attribute will be stored by Keycloak with the name `mobile`. +. Ensure the name of the input html element starts with `user.attributes.`. In the example above, the attribute will be stored by {project_name} with the name `mobile`. -To see the changes make sure your realm is using your custom theme for the login theme and open the registration page. +. To see the changes, make sure your realm is using your custom theme for the login theme and open the registration page. === Account Management Console -To be able to manage custom attributes in the user profile page in the account management console copy the template `themes/base/account/account.ftl` to the -account type of your custom theme. Then open the copy in an editor. +Use this procedure to manage custom attributes in the user profile page in the account management console. +.Procedure +. copy the template `themes/base/account/account.ftl` to the +account type of your custom theme. + +. Open the copy in an editor. ++ As an example to add a mobile number to the account page add the following snippet to the form: - ++ [source,html] ----
@@ -48,6 +62,6 @@ As an example to add a mobile number to the account page add the following snipp
---- -Ensure the name of the input html element starts with `user.attributes.`. +. Ensure the name of the input html element starts with `user.attributes.`. -To see the changes make sure your realm is using your custom theme for the account theme and open the user profile page in the account management console. +. To see the changes, make sure your realm is using your custom theme for the account theme and open the user profile page in the account management console. diff --git a/server_development/topics/extensions.adoc b/server_development/topics/extensions.adoc index 16bf63844b..33897408a4 100644 --- a/server_development/topics/extensions.adoc +++ b/server_development/topics/extensions.adoc @@ -1,6 +1,6 @@ [[_extensions]] -== Extending the Server +== Extending the server The {project_name} SPI framework offers the possibility to implement or override particular built-in providers. However {project_name} also provides capabilities to extend its core functionalities and domain. This includes possibilities to: @@ -24,19 +24,22 @@ Object getResource(); ---- -which allows you to return an object, which acts as a https://github.com/jax-rs[JAX-RS Resource]. For more details, see the Javadoc and our examples. +Use this method to return an object, which acts as a https://github.com/jax-rs[JAX-RS Resource]. For more details, see the Javadoc and our examples. There is a very simple example in the example distribution in `providers/rest` and there is a more advanced example in `providers/domain-extension`, which shows how to add an authenticated REST endpoint and other functionalities like <<_extensions_spi, Adding your own SPI>> -or <<_extensions_jpa,Extending datamodel with your own JPA entities>>. +or <<_extensions_jpa,Extending the datamodel with custom JPA entities>>. For details on how to package and deploy a custom provider, refer to the <<_providers,Service Provider Interfaces>> chapter. [[_extensions_spi]] === Add your own custom SPI -This is useful especially with the <<_extensions_rest,Custom REST endpoints>>. To add your own kind of SPI, you need to -implement the interface `org.keycloak.provider.Spi` and define the ID of your SPI and the `ProviderFactory` and `Provider` classes. That looks like this: +A custom SPI is especially useful with Custom REST endpoints. Use this procedure to add your own SPI +.Procedure + +. implement the interface `org.keycloak.provider.Spi` and define the ID of your SPI and the `ProviderFactory` and `Provider` classes. That looks like this: ++ [source,java] ---- package org.keycloak.examples.domainextension.spi; @@ -70,21 +73,25 @@ public class ExampleSpi implements Spi { ---- -Then you need to create the file `META-INF/services/org.keycloak.provider.Spi` and add the class of your SPI to it. For example: - +. Create the file `META-INF/services/org.keycloak.provider.Spi` and add the class of your SPI to it. For example: ++ [source] ---- org.keycloak.examples.domainextension.spi.ExampleSpi ---- -The next step is to create the interfaces `ExampleServiceProviderFactory`, which extends from `ProviderFactory` and `ExampleService`, which extends from `Provider`. +. Create the interfaces `ExampleServiceProviderFactory`, which extends from `ProviderFactory` and `ExampleService`, which extends from `Provider`. The `ExampleService` will usually contain the business methods you need for your use case. Note that the `ExampleServiceProviderFactory` instance is always scoped per application, however `ExampleService` is scoped per-request (or more accurately per `KeycloakSession` lifecycle). -Finally you need to implement your providers in the same manner as described in the <<_providers,Service Provider Interfaces>> chapter. +. Finally you need to implement your providers in the same manner as described in the <<_providers,Service Provider Interfaces>> chapter. For more details, take a look at the example distribution at `providers/domain-extension`, which shows an Example SPI similar to the one above. +[role="_additional-resources"] +.Additional resources +* <<_extensions_rest,Custom REST endpoints>> + [[_extensions_jpa]] === Add custom JPA entities to the {project_name} data model @@ -146,4 +153,3 @@ The DB schema will be automatically updated at startup. For more details, take a look at the example distribution at example `providers/domain-extension`, which shows the `ExampleJpaEntityProvider` and `example-changelog.xml` described above. NOTE: Don't forget to always backup your database before doing any changes in the Liquibase changelog and triggering a DB update. - diff --git a/server_development/topics/identity-brokering.adoc b/server_development/topics/identity-brokering.adoc index 1779682289..f5fbcc8cf1 100644 --- a/server_development/topics/identity-brokering.adoc +++ b/server_development/topics/identity-brokering.adoc @@ -2,7 +2,7 @@ == Identity Brokering APIs {project_name} can delegate authentication to a parent IDP for login. A typical example of this is the case -where you want users to be able to login through a social provider like Facebook or Google. {project_name} -also allows you to link existing accounts to a brokered IDP. This section talks about some APIs that your applications +where you want users to be able to login through a social provider such as Facebook or Google. You can +also link existing accounts to a brokered IDP. This section describes some APIs that your applications can use as it pertains to identity brokering. diff --git a/server_development/topics/identity-brokering/account-linking.adoc b/server_development/topics/identity-brokering/account-linking.adoc index bffab5260d..a29335ee62 100644 --- a/server_development/topics/identity-brokering/account-linking.adoc +++ b/server_development/topics/identity-brokering/account-linking.adoc @@ -1,5 +1,5 @@ -=== Client Initiated Account Linking +=== Client initiated account linking Some applications want to integrate with social providers like Facebook, but do not want to provide an option to login via these social providers. {project_name} offers a browser-based API that applications can use to link an existing @@ -88,7 +88,7 @@ to the application. If there is an error condition and the auth server deems it While this API guarantees that the application initiated the request, it does not completely prevent CSRF attacks for this operation. The application is still responsible for guarding against CSRF attacks target at itself. -==== Refreshing External Tokens +==== Refreshing external tokens If you are using the external token generated by logging into the provider (i.e. a Facebook or GitHub token), you can refresh this token by re-initiating the account linking API. diff --git a/server_development/topics/identity-brokering/tokens.adoc b/server_development/topics/identity-brokering/tokens.adoc index 6bf42326ad..f93068599b 100644 --- a/server_development/topics/identity-brokering/tokens.adoc +++ b/server_development/topics/identity-brokering/tokens.adoc @@ -1,5 +1,5 @@ -=== Retrieving External IDP Tokens +=== Retrieving external IDP tokens {project_name} allows you to store tokens and responses from the authentication process with the external IDP. For that, you can use the `Store Token` configuration option on the IDP's settings page. diff --git a/server_development/topics/locale-selector.adoc b/server_development/topics/locale-selector.adoc index 76bb5c3849..4ae8036c17 100644 --- a/server_development/topics/locale-selector.adoc +++ b/server_development/topics/locale-selector.adoc @@ -1,5 +1,5 @@ [[_locale_selector]] -=== Locale Selector +=== Locale selector By default, the locale is selected using the `DefaultLocaleSelectorProvider` which implements the `LocaleSelectorProvider` interface. English is the default language when internationalization is disabled. With internationalization enabled, the locale is resolved according to the logic described in the link:{adminguide_link}#_user_locale_selection[{adminguide_name}]. @@ -13,6 +13,10 @@ This behavior can be changed through the `LocaleSelectorSPI` by implementing the The `LocaleSelectorProvider` interface has a single method, `resolveLocale`, which must return a locale given a `RealmModel` and a nullable `UserModel`. The actual request is available from the `KeycloakSession#getContext` method. -Custom implementations can extend the `DefaultLocaleSelectorProvider` in order to reuse parts of the default behaviour. For example to ignore the `Accept-Language` request header, a custom implementation could extend the default provider, override it's `getAcceptLanguageHeaderLocale`, and return a null value. As a result the locale selection will fall back on the realms's default language. +Custom implementations can extend the `DefaultLocaleSelectorProvider` in order to reuse parts of the default behavior. For example to ignore the `Accept-Language` request header, a custom implementation could extend the default provider, override it's `getAcceptLanguageHeaderLocale`, and return a null value. As a result the locale selection will fall back on the realms's default language. + +[role="_additional-resources"] +.Additional resources + +* Follow the steps in <<_providers,Service Provider Interfaces>> for more details on how to create and deploy a custom provider. -Follow the steps in <<_providers,Service Provider Interfaces>> for more details on how to create and deploy a custom provider. diff --git a/server_development/topics/providers.adoc b/server_development/topics/providers.adoc index 0da13b98d9..022dae458f 100644 --- a/server_development/topics/providers.adoc +++ b/server_development/topics/providers.adoc @@ -47,7 +47,7 @@ public class MyThemeSelectorProviderFactory implements ThemeSelectorProviderFact } ---- -NOTE: Keycloak creates a single instance of provider factories which makes it possible to store state for multiple requests. +NOTE: {project_name} creates a single instance of provider factories which makes it possible to store state for multiple requests. Provider instances are created by calling create on the factory for each request so these should be light-weight object. Example ThemeSelectorProvider: @@ -126,11 +126,11 @@ public class MyThemeSelectorProvider implements ThemeSelectorProvider { ---- [[_providers_admin_console]] -==== Show info from your SPI implementation in admin console +==== Show info from your SPI implementation in the Admin Console -Sometimes it is useful to show additional info about your Provider to a {project_name} administrator. You can show provider build time information (eg. version of +Sometimes it is useful to show additional info about your Provider to a {project_name} administrator. You can show provider build time information (for example, version of custom provider currently installed), current configuration of the provider (eg. url of remote system your provider talks to) or some operational info -(average time of response from remote system your provider talks to). {project_name} admin console provides Server Info page to show this kind of information. +(average time of response from remote system your provider talks to). {project_name} Admin Console provides Server Info page to show this kind of information. To show info from your provider it is enough to implement `org.keycloak.provider.ServerInfoAwareProviderFactory` interface in your `ProviderFactory`. @@ -194,7 +194,7 @@ The alternative approach is to deploy as a module. If you are creating a custom SPI you will need to deploy it as a module, otherwise we recommend using the {project_name} deployer approach. -==== Using the {project_name} Deployer +==== Using the {project_name} deployer If you copy your provider jar to the {project_name} `standalone/deployments/` directory, your provider will automatically be deployed. Hot deployment works too. Additionally, your provider jar works similarly to other components deployed in a {appserver_name} @@ -206,20 +206,22 @@ it really easy to use third party jars as you can just put these libraries in th ==== Register a provider using Modules -To register a provider using Modules first create a module. -To do this you can either use the jboss-cli script or manually create a folder inside `KEYCLOAK_HOME/modules` and add your jar and a `module.xml`. +.Procedure +. To register a provider using Modules, create a module. ++ +You can either use the jboss-cli script or manually create a folder inside `KEYCLOAK_HOME/modules` and add your jar and a `module.xml`. ++ For example to add the event listener sysout example provider using the `jboss-cli` script execute: - ++ [source] ---- KEYCLOAK_HOME/bin/jboss-cli.sh --command="module add --name=org.acme.provider --resources=target/provider.jar --dependencies=org.keycloak.keycloak-core,org.keycloak.keycloak-server-spi" ---- -Or to manually create it start by creating the folder `KEYCLOAK_HOME/modules/org/acme/provider/main`. -Then copy `provider.jar` to this folder and create `module.xml` with the following content: +. To manually create the module, create the folder `KEYCLOAK_HOME/modules/org/acme/provider/main`. Then copy `provider.jar` to this folder and create `module.xml` with the following content: ++ [source,xml] ---- - @@ -232,10 +234,9 @@ Then copy `provider.jar` to this folder and create `module.xml` with the followi ---- -Once you've created the module you need to register this module with {project_name}. -This is done by editing the keycloak-server subsystem section of +. Register this module with {project_name} by editing the keycloak-server subsystem section of `standalone.xml`, `standalone-ha.xml`, or `domain.xml`, and adding it to the providers: - ++ [source,xml] ---- @@ -306,13 +307,13 @@ public class EjbExampleUserStorageProvider implements UserStorageProvider, } ---- -You have to define the `@Local` annotation and specify your provider class there. If you don't do this, EJB will +You define the `@Local` annotation and specify your provider class there. If you don't do this, EJB will not proxy the provider instance correctly and your provider won't work. -You must put the `@Remove` annotation on the `close()` method of your provider. If you don't, the stateful bean +You put the `@Remove` annotation on the `close()` method of your provider. If you don't, the stateful bean will never be cleaned up and you may eventually see error messages. -Implementations of `ProviderFactory` are required to be plain java objects. Your factory class would +Ixmplementations of `ProviderFactory` are required to be plain java objects. Your factory class would perform a JNDI lookup of the Stateful EJB in its `create()` method. [source,java] @@ -336,7 +337,7 @@ public class EjbExampleUserStorageProviderFactory ---- [[_script_providers]] -=== JavaScript Providers +=== JavaScript providers {project_name} has the ability to execute scripts during runtime in order to allow administrators to customize specific functionalities: @@ -448,7 +449,7 @@ For JavaScript Policies when using {project_name} Authorization Services. You ca + For OpenID Connect Script Protocol Mappers. You can have one or multiple mappers in the same JAR file -For each script file in your `JAR` file you must have a corresponding entry in `META-INF/keycloak-scripts.json` that maps your scripts files to a specific provider type. For that you should provide the following properties for each entry: +For each script file in your `JAR` file, you need a corresponding entry in `META-INF/keycloak-scripts.json` that maps your scripts files to a specific provider type. For that you should provide the following properties for each entry: * `name` + @@ -463,13 +464,13 @@ An optional text that better describes the intend of the script file + The name of the script file. This property is *mandatory* and should map to a file within the JAR. -==== Deploy the Script JAR +==== Deploy the script JAR Once you have a JAR file with a descriptor and the scripts you want to deploy, you just need to copy the JAR to the {project_name} `standalone/deployments/` directory. -==== Using {project_name} Administration Console to upload scripts +==== Using the {project_name} Admin Console to upload scripts -NOTE: Ability to upload scripts through the admin console is deprecated and will be removed in a future version of {project_name} +NOTE: Ability to upload scripts through the Admin Console is deprecated and will be removed in a future version of {project_name}. Administrators cannot upload scripts to the server. This behavior prevents potential harm to the system in case malicious scripts are accidentally executed. Administrators should always deploy scripts directly to the server using a @@ -482,4 +483,4 @@ For more details about how to enable the `upload_scripts` feature. Please, take === Available SPIs -If you want to see list of all available SPIs at runtime, you can check `Server Info` page in admin console as described in <<_providers_admin_console,Admin Console>> section. +If you want to see list of all available SPIs at runtime, you can check `Server Info` page in Admin Console as described in <<_providers_admin_console,Admin Console>> section. diff --git a/server_development/topics/saml-role-mappings-spi.adoc b/server_development/topics/saml-role-mappings-spi.adoc index 4a6d34cbbf..84ef79e151 100644 --- a/server_development/topics/saml-role-mappings-spi.adoc +++ b/server_development/topics/saml-role-mappings-spi.adoc @@ -1,5 +1,5 @@ [[_saml_role_mappings_spi]] -== SAML Role Mappings SPI +== SAML role mappings SPI {project_name} defines a SPI for mapping SAML roles into roles that exist in the SP environment. The roles returned by a third-party IDP might not always correspond to the roles that were defined for the SP application so there is a need for a @@ -13,7 +13,7 @@ roles assigned to the SAML principal) depending on the use case. For details about the configuration of the role mappings provider for the SAML adapter as well as a description of the default implementations available see the link:{adapterguide_link}[{adapterguide_name}]. -=== Implementing a Custom Role Mappings Provider +=== Implementing a custom role mappings provider To implement a custom role mappings provider one first needs to implement the `org.keycloak.adapters.saml.RoleMappingsProvider` interface. Then, a `META-INF/services/org.keycloak.adapters.saml.RoleMappingsProvider` file containing the fully qualified name diff --git a/server_development/topics/themes-resources.adoc b/server_development/topics/themes-resources.adoc index 3b8be1344f..a040f34e8b 100644 --- a/server_development/topics/themes-resources.adoc +++ b/server_development/topics/themes-resources.adoc @@ -14,5 +14,7 @@ If you want a more flexible way to load templates and resources that can be achi By implementing `ThemeResourceProviderFactory` and `ThemeResourceProvider` you can decide exactly how to load templates and resources. -Follow the steps in <<_providers,Service Provider Interfaces>> for more details on how to create and deploy a custom -provider. +[role="_additional-resources"] +.Additional resources +* Follow the steps in <<_providers,Service Provider Interfaces>> for more details on how to create and deploy a custom provider. + diff --git a/server_development/topics/themes-selector.adoc b/server_development/topics/themes-selector.adoc index ccfa1c9531..14f191eaf6 100644 --- a/server_development/topics/themes-selector.adoc +++ b/server_development/topics/themes-selector.adoc @@ -9,5 +9,7 @@ header, for example. To create a custom theme selector you need to implement `ThemeSelectorProviderFactory` and `ThemeSelectorProvider`. -Follow the steps in <<_providers,Service Provider Interfaces>> for more details on how to create and deploy a custom -provider. +[role="_additional-resources"] +.Additional resources +* Follow the steps in <<_providers,Service Provider Interfaces>> for more details on how to create and deploy a custom provider. + diff --git a/server_development/topics/themes.adoc b/server_development/topics/themes.adoc index c5672faae3..af76ba6d76 100755 --- a/server_development/topics/themes.adoc +++ b/server_development/topics/themes.adoc @@ -6,28 +6,35 @@ integrated with your applications. image::images/login-sunrise.png[caption="",title="Login page with sunrise example theme"] -=== Theme Types +=== Theme types A theme can provide one or more types to customize different aspects of {project_name}. The types available are: * Account - Account management -* Admin - Admin console +* Admin - Admin Console * Email - Emails * Login - Login forms * Welcome - Welcome page -=== Configure Theme +=== Configuring a theme -All theme types, except welcome, are configured through the `Admin Console`. To change the theme used for a realm open the `Admin Console`, select -your realm from the drop-down box in the top left corner. Under `Realm Settings` click `Themes`. +All theme types, except welcome, are configured through the Admin Console. -NOTE: To set the theme for the `master` admin console you need to set the admin console theme for the `master` realm. To see the changes to the admin console -refresh the page. +.Procedure -To change the welcome theme you need to edit `standalone.xml`, `standalone-ha.xml`, or `domain.xml`. +. Log into the Admin Console. +. Select your realm from the drop-down box in the top left corner. +. Click *Realm Settings* from the menu. +. Click the *Themes* tab. ++ +NOTE: To set the theme for the `master` Admin Console you need to set the Admin Console theme for the `master` realm. ++ +. To see the changes to the Admin Console refresh the page. -Add `welcomeTheme` to the theme element, for example: +. Change the welcome theme by editing `standalone.xml`, `standalone-ha.xml`, or `domain.xml`. +. Add `welcomeTheme` to the theme element, for example: ++ [source,xml] ---- @@ -36,15 +43,14 @@ Add `welcomeTheme` to the theme element, for example: ... ---- +. Restart the server for the changes to the welcome theme to take effect. -If the server is running you need to restart the server for the changes to the welcome theme to take effect. - -=== Default Themes +=== Default themes {project_name} comes bundled with default themes in the server's root `themes` directory. To simplify upgrading you should not edit the bundled themes directly. Instead create your own theme that extends one of the bundled themes. -=== Creating a Theme +=== Creating a theme A theme consists of: @@ -63,9 +69,15 @@ When extending a theme you can override individual resources (templates, stylesh need to update your custom template when upgrading to a new release. While creating a theme it's a good idea to disable caching as this makes it possible to edit theme resources directly from the `themes` directory without -restarting {project_name}. To do this edit `standalone.xml`. For `theme` set `staticMaxAge` to `-1` and both -`cacheTemplates` and `cacheThemes` to `false`: +restarting {project_name}. +.Procedure + +. Edit `standalone.xml`. + +. For `theme` set `staticMaxAge` to `-1` and both +`cacheTemplates` and `cacheThemes` to `false`: ++ [source,xml] ---- @@ -76,31 +88,44 @@ restarting {project_name}. To do this edit `standalone.xml`. For `theme` set `st ---- -Remember to re-enable caching in production as it will significantly impact performance. - -To create a new theme start by creating a new directory in the `themes` directory. The name of the directory becomes the name of the theme. For example to +. Create a directory in the `themes` directory. ++ +The name of the directory becomes the name of the theme. For example to create a theme called `mytheme` create the directory `themes/mytheme`. -Inside the theme directory create a directory for each of the types your theme is going to provide. For example to add the login type to the `mytheme` -theme create the directory `themes/mytheme/login`. - -For each type create a file `theme.properties` which allows setting some configuration for the theme. For example to configure the theme `themes/mytheme/login` -that we just created to extend the base theme and import some common resources create the file `themes/mytheme/login/theme.properties` with following contents: +. Inside the theme directory, create a directory for each of the types your theme is going to provide. ++ +For example, to add the login type to the `mytheme` theme, create the directory `themes/mytheme/login`. +. For each type create a file `theme.properties` which allows setting some configuration for the theme. ++ +For example, to configure the theme `themes/mytheme/login` to extend the base theme and import some common resources, create the file `themes/mytheme/login/theme.properties` with following contents: ++ [source] ---- parent=base import=common/keycloak ---- ++ +You have now created a theme with support for the login type. -You have now created a theme with support for the login type. To check that it works open the admin console. Select your realm and click on `Themes`. -For `Login Theme` select `mytheme` and click `Save`. Then open the login page for the realm. +. Log into the Admin Console to checkout your new theme +. Select your realm +. Click *Realm Settings* from the menu. +. Click on the *Themes* tab. +. For *Login Theme* select *mytheme* and click *Save*. +. Open the login page for the realm. ++ +You can do this either by logging in through your application or by opening the Account Management console (`/realms/{realm name}/account`). -You can do this either by login through your application or by opening the Account Management console (`/realms/{realm name}/account`). +. To see the effect of changing the parent theme, set `parent=keycloak` in `theme.properties` and refresh the login page. -To see the effect of changing the parent theme, set `parent=keycloak` in `theme.properties` and refresh the login page. +[NOTE] +==== +Be sure to re-enable caching in production as it will significantly impact performance. +==== -==== Theme Properties +==== Theme properties Theme properties are set in the file `/theme.properties` in the theme directory. @@ -133,13 +158,18 @@ unixHome=${env.HOME:Unix home not found} windowsHome=${env.HOMEPATH:Windows home not found} ---- -==== Stylesheets +==== Add a stylesheet to a theme -A theme can have one or more stylesheets. To add a stylesheet create a file in the `/resources/css` directory of your theme. Then add it to the `styles` -property in `theme.properties`. +You can add one or more stylesheets to a theme. -For example to add `styles.css` to the `mytheme` create `themes/mytheme/login/resources/css/styles.css` with the following content: +.Procedure +. Create a file in the `/resources/css` directory of your theme. + +. Add this file to the `styles` property in `theme.properties`. ++ +For example, to add `styles.css` to the `mytheme`, create `themes/mytheme/login/resources/css/styles.css` with the following content: ++ [source,css] ---- .login-pf body { @@ -147,36 +177,43 @@ For example to add `styles.css` to the `mytheme` create `themes/mytheme/login/re } ---- -Then edit `themes/mytheme/login/theme.properties` and add: - +. Edit `themes/mytheme/login/theme.properties` and add: ++ [source] ---- styles=css/styles.css ---- -To see the changes open the login page for your realm. You will notice that the only styles being applied are those from your custom stylesheet. To include the -styles from the parent theme you need to load the styles from that theme as well. Do this by editing `themes/mytheme/login/theme.properties` and changing `styles` -to: +. To see the changes, open the login page for your realm. ++ +You will notice that the only styles being applied are those from your custom stylesheet. +. To include the styles from the parent theme, load the styles from that theme. Edit `themes/mytheme/login/theme.properties` and change `styles` to: ++ [source] ---- styles=web_modules/@fontawesome/fontawesome-free/css/icons/all.css web_modules/@patternfly/react-core/dist/styles/base.css web_modules/@patternfly/react-core/dist/styles/app.css node_modules/patternfly/dist/css/patternfly.min.css node_modules/patternfly/dist/css/patternfly-additions.min.css css/login.css css/styles.css ---- ++ +NOTE: To override styles from the parent stylesheets, ensure that your stylesheet is listed last. -NOTE: To override styles from the parent stylesheets it's important that your stylesheet is listed last. +==== Adding a script to a theme -==== Scripts +You can add one or more scripts to a theme. -A theme can have one or more scripts, to add a script create a file in the `/resources/js` directory of your theme. Then add it to the `scripts` -property in `theme.properties`. +.Procedure -For example to add `script.js` to the `mytheme` create `themes/mytheme/login/resources/js/script.js` with the following content: +. Create a file in the `/resources/js` directory of your theme. +. Add the file to the `scripts` property in `theme.properties`. ++ +For example, to add `script.js` to the `mytheme`, create `themes/mytheme/login/resources/js/script.js` with the following content: ++ [source,javascript] ---- alert('Hello'); ---- - ++ Then edit `themes/mytheme/login/theme.properties` and add: [source] @@ -184,7 +221,7 @@ Then edit `themes/mytheme/login/theme.properties` and add: scripts=js/script.js ---- -==== Images +==== Adding an image to a theme To make images available to the theme add them to the `/resources/img` directory of your theme. These can be used from within stylesheets or directly in HTML templates. @@ -226,61 +263,73 @@ of the realm. Texts of these message bundles can be overwritten by realm-specific values. The realm-specific values are manageable via UI and API. -==== Internationalization +==== Adding a language to a realm -{project_name} supports internationalization. To enable internationalization for a realm see {adminguide_link}[{adminguide_name}]. This -section describes how you can add your own language. +.Prerequisites -To add a new language create the file `/messages/messages_.properties` in the directory of your theme. Then add it to the `locales` property in -`/theme.properties`. For a language to be available to users the realms `login`, `account` and `email` theme has to support the language, so you -need to add your language for those theme types. +* To enable internationalization for a realm, see {adminguide_link}[{adminguide_name}]. +.Procedure + +. Create the file `/messages/messages_.properties` in the directory of your theme. + +. Add this file to the `locales` property in `/theme.properties`. +For a language to be available to users the realms `login`, `account` and `email`, the theme has to support the language, so you need to add your language for those theme types. ++ For example, to add Norwegian translations to the `mytheme` theme create the file `themes/mytheme/login/messages/messages_no.properties` with the following content: - ++ [source] ---- usernameOrEmail=Brukernavn password=Passord ---- ++ +If you omit a translation for messages, they will use English. -All messages you don't provide a translation for will use the default English translation. - -Then edit `themes/mytheme/login/theme.properties` and add: - +. Edit `themes/mytheme/login/theme.properties` and add: ++ [source] ---- locales=en,no ---- -You also need to do the same for the `account` and `email` theme types. To do this create `themes/mytheme/account/messages/messages_no.properties` and -`themes/mytheme/email/messages/messages_no.properties`. Leaving these files empty will result in the English messages being used. Then copy -`themes/mytheme/login/theme.properties` to `themes/mytheme/account/theme.properties` and `themes/mytheme/email/theme.properties`. +. Add the same for the `account` and `email` theme types. To do this create `themes/mytheme/account/messages/messages_no.properties` and +`themes/mytheme/email/messages/messages_no.properties`. Leaving these files empty will result in the English messages being used. -Finally you need to add a translation for the language selector. This is done by adding a message to the English translation. To do this add the following to +. Copy `themes/mytheme/login/theme.properties` to `themes/mytheme/account/theme.properties` and `themes/mytheme/email/theme.properties`. + +. Add a translation for the language selector. This is done by adding a message to the English translation. To do this add the following to `themes/mytheme/account/messages/messages_en.properties` and `themes/mytheme/login/messages/messages_en.properties`: - ++ [source] ---- locale_no=Norsk ---- - ++ By default message properties files should be encoded using ISO-8859-1. It's also possible to specify the encoding using a special header. For example to use UTF-8 encoding: - ++ [source] ---- # encoding: UTF-8 usernameOrEmail=.... ---- -See <<_locale_selector,Locale Selector>> on details on how the current locale is selected. +[role="_additional-resources"] +.Additional resources +* See <<_locale_selector,Locale Selector>> on details on how the current locale is selected. -==== Custom Identity providers icons +[[custom-identity-providers-icons]] +==== Adding custom Identity Providers icons {project_name} supports adding icons for custom Identity providers, which are displayed on the login screen. -You just have to define icon classes in your login `theme.properties` file (i.e. `themes/mytheme/login/theme.properties`) with key pattern `kcLogoIdP-`. -For Identity provider with an alias `myProvider`, you may add a line, like below, to `theme.properties` file of your custom theme. +.Procedure + +. Define icon classes in your login `theme.properties` file (for example, `themes/mytheme/login/theme.properties`) with key pattern `kcLogoIdP-`. + +. For an Identity Provider with an alias `myProvider`, you may add a line to `theme.properties` file of your custom theme. For example: ++ [source] ---- kcLogoIdP-myProvider = fa fa-lock @@ -289,18 +338,20 @@ kcLogoIdP-myProvider = fa fa-lock All icons are available on the official website of PatternFly4. Icons for social providers are already defined in base login theme properties (`themes/keycloak/login/theme.properties`), where you can inspire yourself. -==== HTML Templates +==== Creating a custom HTML template -{project_name} uses https://freemarker.apache.org/[Freemarker Templates] in order to generate HTML. You can override individual templates in your own theme by +{project_name} uses Freemarker Templates to generate HTML. You can override individual templates in your own theme by creating `/