From 6cf4c85ffbf5ba37773296af1d2250f5c7ca8e36 Mon Sep 17 00:00:00 2001 From: Stian Thorgersen Date: Fri, 3 Jun 2016 14:28:51 +0200 Subject: [PATCH 1/5] Complete JavaScript adapter chapter --- topics/oidc/javascript-adapter.adoc | 360 ++++++++++++++-------------- 1 file changed, 184 insertions(+), 176 deletions(-) diff --git a/topics/oidc/javascript-adapter.adoc b/topics/oidc/javascript-adapter.adoc index 3bda03a5c7..8653cbadd6 100755 --- a/topics/oidc/javascript-adapter.adoc +++ b/topics/oidc/javascript-adapter.adoc @@ -1,28 +1,31 @@ [[_javascript_adapter]] == Javascript Adapter -The Keycloak Server comes with a Javascript library you can use to secure HTML/Javascript applications. -This library is referenceable directly from the keycloak server. -You can also download the adapter from Keycloak's download site if you want a static copy. -It works in the same way as other application adapters except that your browser is driving the OAuth redirect protocol rather than the server. +{{book.project.name}} comes with a client-side JavaScript library that can be used to secure HTML5/JavaScript applications. The JavaScript adapter has built-in +support for Cordova applications. -The disadvantage of using this approach is that you have a non-confidential, public client. -This makes it more important that you register valid redirect URLs and make sure your domain name is secured. +The library can be retrieved directly from the {{book.project.name}} server at `/auth/js/keycloak.js` and is also distributed as a ZIP archive. -To use this adapter, you must first configure an application (or client) through the `Keycloak Admin Console`. -You should select `public` for the `Access Type` field. -As public clients can't be verified with a client secret, you are required to configure one or more valid redirect uris. -Once you've configured the application, click on the `Installation` tab and download the `keycloak.json` file. -This file should be hosted on your web-server at the same root as your HTML pages. -Alternatively, you can manually configure the adapter and specify the URL for this file. +One important thing to note about using client-side applications is that the client has to be a public client as there is no secure way to store client +credentials in a client-side application. This makes it very important to make sure the redirect URIs you have configured for the client are correct and as +specific as possible. -Next, you have to initialize the adapter in your application. -An example is shown below. +To use the JavaScript adapter you must first create a client for your application in the {{book.project.name}} Administration Console. Make sure `public` +is selected for `Access Type`. + +You also need to configure valid redirect URIs and valid web origins. Be as specific as possible as failing to do so may results in a security vulnerability. + +Once the client is created click on the `Installation` tab select `Keycloak OIDC JSON` for `Format Option` then click on `Download`. The downloaded +`keycloak.json` file should be hosted on your web server at the same location as your HTML pages. + +Alternatively, you can skip the configuration file and manually configure the adapter. + +The following example shows how to initialize the JavaScript adapter: [source,html] ---- - + ---- -To specify the location of the keycloak.json file: -[source] +If the `keycloak.json` file is in a different location you can specify it: + +[source,javascript] ---- var keycloak = Keycloak('http://localhost:8080/myapp/keycloak.json')); ----- -Or finally to manually configure the adapter: - -[source] ---- +You can also skip the file altogether and manually configure the adapter: + +[source,javascript] +---- var keycloak = Keycloak({ url: 'http://keycloak-server/auth', realm: 'myrealm', clientId: 'myapp' }); ----- -You can also pass `login-required` or `check-sso` to the init function. -Login required will cause a redirect to the login form on the server, while check-sso will simply redirect to the auth server to check if the user is already logged in to the realm. -For example: +---- + +By default to authenticate you need to call the `login` function. However, there are two options available to make the adapter automatically authenticate. You +can pass `login-required` or `check-sso` to the init function. `login-required` will authenticate the client if the user is logged-in to {{book.project.name}} +or display the login page if not. `check-sso` will only authenticate the client if the user is already logged-in, if the user is not logged-in the browser will be +redirected back to the application and remain unauthenticated. + +To enable `login-required` set `onLoad` to `login-required` and pass to the init method: [source] ---- keycloak.init({ onLoad: 'login-required' }) ---- -After you login, your application will be able to make REST calls using bearer token authentication. -Here's an example pulled from the `customer-portal-js` example that comes with the distribution. +After the user is authenticated the application can make requests to RESTful services secured by {{book.project.name}} by including the bearer token in the +`Authorization` header. For example: -[source] +[source,javascript] ---- - - ----- + req.send(); +}; +---- -The `loadData()` method builds an HTTP request setting the `Authorization` header to a bearer token. -The `keycloak.token` points to the access token the browser obtained when it logged you in. -The `loadFailure()` method is invoked on a failure. -The `reloadData()` function calls `keycloak.updateToken()` passing in the `loadData()` and `loadFailure()` callbacks. -The `keycloak.updateToken()` method checks to see if the access token hasn't expired. -If it hasn't, and your oauth login returned a refresh token, this method will refresh the access token. -Finally, if successful, it will invoke the success callback, which in this case is the `loadData()` method. +One thing to keep in mind is that the access token by default has a short life expiration so you may need to refresh the access token prior to sending the +request. You can do this by the `updateToken` method. The `updateToken` method returns a promise object which makes it easy to invoke the service only if the +token was successfully refreshed and for example display an error to the user if it wasn't. For example: -To refresh the token when it is expired, call the `updateToken` method. -This method returns a promise object, which can be used to invoke a function on success or failure. -This method can be used to wrap functions that should only be called with a valid token. -For example, the following method will refresh the token if it expires within 30 seconds, and then invoke the specified function. -If the token is valid for more than 30 seconds it will just call the specified function. - -[source] +[source,javascript] ---- keycloak.updateToken(30).success(function() { - // send request with valid token + loadData(); }).error(function() { - alert('failed to refresh token'); + alert('Failed to refresh token'); ); ---- == Session status iframe -By default, the JavaScript adapter creates a non-visible iframe that is used to detect if a single-sign out has occurred. -This does not require any network traffic, instead the status is retrieved from a special status cookie. -This feature can be disabled by setting `checkLoginIframe: false` in the options passed to the `init` method. +By default, the JavaScript adapter creates a hidden iframe that is used to detect if a Single-Sign Out has occurred. +This does not require any network traffic, instead the status is retrieved by looking at a special status cookie. +This feature can be disabled by setting `checkLoginIframe: false` in the options passed to the `init` method. + +You should not rely on looking at this cookie directly. It's format can change and it's also associated with the URL of the {{book.project.name}} server, not +your application. [[_javascript_implicit_flow]] == Implicit and Hybrid Flow -By default, the JavaScript adapter uses http://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth[OpenID Connect standard (Authorization code) flow], which means that after authentication, the Keycloak server redirects the user back to your application, where the JavaScript adapter will exchange the `code` for an access token and a refresh token. +By default, the JavaScript adapter uses the http://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth[Authorization Code] flow. +With this flow the {{book.project.name}} server returns a authorization code, not a authentication token, to the application. The JavaScript adapter exchanges +the `code` for an access token and a refresh token after the browser is redirected back to the application. -However, Keycloak also supports http://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowAuth[OpenID Connect Implicit flow] where an access token is sent immediately after successful authentication with Keycloak (there is no additional request for exchange code). This could have better performance than standard flow, as there is no additional request to exchange the code for tokens. -However, sending the access token in the URL fragment could pose a security issue in some environments (access logs might expose tokens located in the URL). +{{book.project.name}} also supports the http://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowAuth[Implicit] flow where an access token +is sent immediately after successful authentication with {{book.project.name}}. This may have better performance than standard flow, as there is no additional +request to exchange the code for tokens, but it has implications when the access token expires. -To enable implicit flow, you need to enable the `Implicit Flow Enabled` flag for the client in the Keycloak admin console. -You also need to pass the parameter `flow` with value `implicit` to `init` method. -An example is below: +However, sending the access token in the URL fragment can be a security vulnerability. For example the token could be leaked through web server logs and or +browser history. -[source] +To enable implicit flow, you need to enable the `Implicit Flow Enabled` flag for the client in the {{book.project.name}} Administration Console. +You also need to pass the parameter `flow` with value `implicit` to `init` method: + +[source,javascript] +---- +keycloak.init({ flow: 'implicit' }) ---- -keycloak.init({ flow: 'implicit' }) ----- -Note that with implicit flow, you are not given a refresh token after authentication. +One thing to note is that only an access token is provided and there is no refresh token. This means that once the access token has expired the application +has to do the redirect to the {{book.project.name}} again to obtain a new access token. -This makes it harder for your application to periodically update the access token in background (without browser redirection). It's recommended that you implement an `onTokenExpired` callback method on the keycloak object, so you are notified after the token is expired (For example you can call keycloak.login, which will redirect browser to Keycloak login screen and it will immediately redirect you back if the SSO session is still valid and the user is still logged. -However, make sure to save the application state before performing a redirect.) - -Keycloak also has support for http://openid.net/specs/openid-connect-core-1_0.html#HybridFlowAuth[OpenID Connect Hybrid flow]. +{{book.project.name}} also supports the http://openid.net/specs/openid-connect-core-1_0.html#HybridFlowAuth[Hybrid] flow. This requires the client to have both the `Standard Flow Enabled` and `Implicit Flow Enabled` flags enabled in the admin console. -The Keycloak server will then send both the code and tokens to your application. +The {{book.project.name}} server will then send both the code and tokens to your application. The access token can be used immediately while the code can be exchanged for access and refresh tokens. Similar to the implicit flow, the hybrid flow is good for performance because the access token is available immediately. -But, the token is still sent in the URL, and security risks might still apply. -However, one advantage over the implicit flow is that a refresh token is made available to the application (after the code-to-token request is finished). +But, the token is still sent in the URL, and the security vulnerability mentioned earlier may still apply. -For hybrid flow, you need to pass the parameter `flow` with value `hybrid` to `init` method. +One advantage in the Hybrid flow is that the refresh token is made available to the application. + +For the Hybrid flow, you need to pass the parameter `flow` with value `hybrid` to the `init` method: + +[source,javascript] +---- +keycloak.init({ flow: 'hybrid' }) +---- == Older browsers The JavaScript adapter depends on Base64 (window.btoa and window.atob) and HTML5 History API. -If you need to support browsers that don't provide those (for example IE9) you'll need to add polyfillers. +If you need to support browsers that don't have these available (for example IE9) you need to add polyfillers. + Example polyfill libraries: * https://github.com/davidchambers/Base64.js @@ -190,20 +184,48 @@ new Keycloak({ url: 'http://localhost/auth', realm: 'myrealm', clientId: 'myApp' === Properties -* authenticated - true if the user is authenticated -* Authorization -* tokenParsed - the parsed token -* subject - the user id -* idToken - the id token if claims is enabled for the application, null otherwise -* idTokenParsed - the parsed id token -* realmAccess - the realm roles associated with the token -* resourceAccess - the resource roles assocaited with the token -* refreshToken - the base64 encoded token that can be used to retrieve a new token -* refreshTokenParsed - the parsed refresh token -* timeSkew - estimated skew between local time and Keycloak server in seconds -* fragment -* Implicit flow -* flow +authenticated:: + Is `true` if the user is authenticated, `false` otherwise. + +token:: + The base64 encoded token that can be sent in the `Authorization` header in requests to services. + +tokenParsed:: + The parsed token as a JavaScript object. + +subject:: + The user id. + +idToken:: + The base64 encoded ID token. + +idTokenParsed:: + The parsed id token as a JavaScript object. + +realmAccess:: + The realm roles associated with the token. + +resourceAccess:: + The resource roles assocaited with the token. + +refreshToken:: + The base64 encoded refresh token that can be used to retrieve a new token. + +refreshTokenParsed:: + The parsed refresh token as a JavaScript object. + +timeSkew:: + The estimated time difference between the browser time and the {{book.project.name}} server in seconds. This value is just an estimation, but is accurate + enough when determining if a token is expired or not. + +responseMode:: + Response mode passed in init (default value is fragment). + +flow:: + Flow passed in init. + +responseType:: + Response type sent to {{book.project.name}} with login requests. This is determined based on the flow value used during initialization, but can be overridden by setting this value. === Methods @@ -213,100 +235,92 @@ Called to initialize the adapter. Options is an Object, where: -* onLoad - specifies an action to do on load, can be either 'login-required' or 'check-sso' -* token - set an initial value for the token -* refreshToken - set an initial value for the refresh token -* idToken - set an initial value for the id token (only together with token or refreshToken) -* timeSkew - set an initial value for skew between local time and Keycloak server in seconds (only together with token or refreshToken) -* checkLoginIframe - set to enable/disable monitoring login state (default is true) -* checkLoginIframeInterval - set the interval to check login state (default is 5 seconds) -* query -+`fragment` -+`fragment` -+`query` -* standard -+`implicit` -+`hybrid`<<_javascript_implicit_flow,+Implicit flow>> - +* onLoad - Specifies an action to do on load. Supported values are 'login-required' or 'check-sso'. +* token - Set an initial value for the token. +* refreshToken - Set an initial value for the refresh token. +* idToken - Set an initial value for the id token (only together with token or refreshToken). +* timeSkew - Set an initial value for skew between local time and Keycloak server in seconds (only together with token or refreshToken). +* checkLoginIframe - Set to enable/disable monitoring login state (default is true). +* checkLoginIframeInterval - Set the interval to check login state (default is 5 seconds). +* responseMode - Set the OpenID Connect response mode send to Keycloak server at login request. Valid values are query or fragment . Default value is fragment, which means that after successful authentication will Keycloak redirect to javascript application with OpenID Connect parameters added in URL fragment. This is generally safer and recommended over query. +* flow - Set the OpenID Connect flow. Valid values are standard, implicit or hybrid. Returns promise to set functions to be invoked on success or error. ==== login(options) -Redirects to login form on (options is an optional object with redirectUri and/or prompt fields) +Redirects to login form on (options is an optional object with redirectUri and/or prompt fields). Options is an Object, where: -* redirectUri - specifies the uri to redirect to after login -* prompt - can be set to 'none' to check if the user is logged in already (if not logged in, a login form is not displayed) -* loginHint - used to pre-fill the username/email field on the login form -* action - if value is 'register' then user is redirected to registration page, otherwise to login page -* locale - specifies the desired locale for the UI +* redirectUri - Specifies the uri to redirect to after login. +* prompt - Can be set to 'none' to check if the user is logged in already (if not logged in, a login form is not displayed). +* loginHint - Used to pre-fill the username/email field on the login form. +* action - If value is 'register' then user is redirected to registration page, otherwise to login page. +* locale - Specifies the desired locale for the UI. ==== createLoginUrl(options) -Returns the url to login form on (options is an optional object with redirectUri and/or prompt fields) +Returns the URL to login form on (options is an optional object with redirectUri and/or prompt fields). Options is an Object, where: -* redirectUri - specifies the uri to redirect to after login -* prompt - can be set to 'none' to check if the user is logged in already (if not logged in, a login form is not displayed) +* redirectUri - Specifies the uri to redirect to after login. +* prompt - Can be set to 'none' to check if the user is logged in already (if not logged in, a login form is not displayed). ==== logout(options) -Redirects to logout +Redirects to logout. Options is an Object, where: -* redirectUri - specifies the uri to redirect to after logout +* redirectUri - Specifies the uri to redirect to after logout. ==== createLogoutUrl(options) -Returns logout out +Returns the URL to logout the user. Options is an Object, where: -* redirectUri - specifies the uri to redirect to after logout +* redirectUri - Specifies the uri to redirect to after logout. ==== register(options) -Redirects to registration form. -It's a shortcut for doing login with option action = 'register' +Redirects to registration form. Shortcut for login with option action = 'register' -Options are same as login method but 'action' is overwritten to 'register' +Options are same as login method but 'action' is set to 'register' ==== createRegisterUrl(options) -Returns the url to registration page. -It's a shortcut for doing createRegisterUrl with option action = 'register' +Returns the url to registration page. Shortcut for createLoginUrl with option action = 'register' -Options are same as createLoginUrl method but 'action' is overwritten to 'register' +Options are same as createLoginUrl method but 'action' is set to 'register' ==== accountManagement() -Redirects to account management +Redirects to the Account Management Console. ==== createAccountUrl() -Returns the url to account management +Returns the URL to the Account Management Console. ==== hasRealmRole(role) -Returns true if the token has the given realm role +Returns true if the token has the given realm role. ==== hasResourceRole(role, resource) -Returns true if the token has the given role for the resource (resource is optional, if not specified clientId is used) +Returns true if the token has the given role for the resource (resource is optional, if not specified clientId is used). ==== loadUserProfile() -Loads the users profile +Loads the users profile. Returns promise to set functions to be invoked on success or error. ==== isTokenExpired(minValidity) -Returns true if the token has less than minValidity seconds left before it expires (minValidity is optional, if not specified 0 is used) +Returns true if the token has less than minValidity seconds left before it expires (minValidity is optional, if not specified 0 is used). ==== updateToken(minValidity) @@ -316,48 +330,42 @@ If the session status iframe is enabled, the session status is also checked. Returns promise to set functions that can be invoked if the token is still valid, or if the token is no longer valid. For example: -[source] +[source,javascript] ---- - keycloak.updateToken(5).success(function(refreshed) { if (refreshed) { - alert('token was successfully refreshed'); + alert('Token was successfully refreshed'); } else { - alert('token is still valid'); + alert('Token is still valid'); } }).error(function() { - alert('failed to refresh the token, or the session has expired'); + alert('Failed to refresh the token, or the session has expired'); }); ---- ==== clearToken() Clear authentication state, including tokens. -This can be useful if application has detected the session has expired, for example if updating token fails. +This can be useful if application has detected the session was expired, for example if updating token fails. + Invoking this results in onAuthLogout callback listener being invoked. -[source] ----- - -keycloak.updateToken(5).error(function() { - keycloak.clearToken(); -}); ----- - === Callback Events The adapter supports setting callback listeners for certain events. + For example: [source] ---- - keycloak.onAuthSuccess = function() { alert('authenticated'); } ----- +---- -* onReady(authenticated) - called when the adapter is initialized -* onAuthSuccess - called when a user is successfully authenticated -* onAuthError - called if there was an error during authentication -* onAuthRefreshSuccess - called when the token is refreshed -* onAuthRefreshError - called if there was an error while trying to refresh the token -* onAuthLogout - called if the user is logged out (will only be called if the session status iframe is enabled, or in Cordova mode) -* onTokenExpired - called when access token expired. When this happens you can for example refresh token, or if refresh not available (ie. with implicit flow) you can redirect to login screen +The available events are: + +* onReady(authenticated) - Called when the adapter is initialized. +* onAuthSuccess - Called when a user is successfully authenticated. +* onAuthError - Called if there was an error during authentication. +* onAuthRefreshSuccess - Called when the token is refreshed. +* onAuthRefreshError - Called if there was an error while trying to refresh the token. +* onAuthLogout - Called if the user is logged out (will only be called if the session status iframe is enabled, or in Cordova mode). +* onTokenExpired - Called when access token expired. When this happens you can for example refresh token, or if refresh not available (ie. with implicit flow) you can redirect to login screen. From 515f3c9002a2ce2342d7cd7d1bbdb65c34d5ba37 Mon Sep 17 00:00:00 2001 From: mposolda Date: Fri, 3 Jun 2016 15:09:26 +0200 Subject: [PATCH 2/5] More Fuse adapter documentation. Remove references to Apache Karaf --- SUMMARY.adoc | 8 +- topics/oidc/java/fuse-adapter.adoc | 98 ++-------------- topics/oidc/java/fuse/camel.adoc | 95 +++++++++++++++ topics/oidc/java/fuse/classic-war.adoc | 82 +++++++++++++ topics/oidc/java/fuse/cxf-builtin.adoc | 98 ++++++++++++++++ topics/oidc/java/fuse/cxf-separate.adoc | 111 ++++++++++++++++++ topics/oidc/java/fuse/fuse-admin.adoc | 87 ++++++++++++++ topics/oidc/java/fuse/servlet-whiteboard.adoc | 76 ++++++++++++ 8 files changed, 568 insertions(+), 87 deletions(-) create mode 100644 topics/oidc/java/fuse/camel.adoc create mode 100644 topics/oidc/java/fuse/classic-war.adoc create mode 100644 topics/oidc/java/fuse/cxf-builtin.adoc create mode 100644 topics/oidc/java/fuse/cxf-separate.adoc create mode 100644 topics/oidc/java/fuse/fuse-admin.adoc create mode 100644 topics/oidc/java/fuse/servlet-whiteboard.adoc diff --git a/SUMMARY.adoc b/SUMMARY.adoc index cc60f2abca..1ef570a8d9 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -10,7 +10,13 @@ .. link:topics/oidc/java/java-adapters.adoc[Java Adapters] ... link:topics/oidc/java/java-adapter-config.adoc[Java Adapters Config] ... link:topics/oidc/java/jboss-adapter.adoc[JBoss EAP/Wildfly Adapter] - ... link:topics/oidc/java/fuse-adapter.adoc[JBoss Fuse and Apache Karaf Adapter] + ... link:topics/oidc/java/fuse-adapter.adoc[JBoss Fuse Adapter] + .... link:topics/oidc/java/fuse/classic-war.adoc[Classic WAR application] + .... link:topics/oidc/java/fuse/servlet-whiteboard.adoc[Servlet Deployed as OSGI Service] + .... link:topics/oidc/java/fuse/camel.adoc[Apache Camel] + .... link:topics/oidc/java/fuse/cxf-separate.adoc[Apache CXF on Separate Jetty] + .... link:topics/oidc/java/fuse/cxf-builtin.adoc[Apache CXF on default Jetty] + .... link:topics/oidc/java/fuse/fuse-admin.adoc[Fuse Admin Services] {% if book.community %} ... link:topics/oidc/java/tomcat-adapter.adoc[Tomcat 6, 7 and 8 Adapters] ... link:topics/oidc/java/jetty9-adapter.adoc[Jetty 9.x Adapters] diff --git a/topics/oidc/java/fuse-adapter.adoc b/topics/oidc/java/fuse-adapter.adoc index c8833f4154..f00dcefb33 100755 --- a/topics/oidc/java/fuse-adapter.adoc +++ b/topics/oidc/java/fuse-adapter.adoc @@ -1,17 +1,17 @@ [[_fuse_adapter]] -=== JBoss Fuse and Apache Karaf Adapter +=== JBoss Fuse Adapter NOTE: JBoss Fuse is a Technology Preview feature and is not fully supported -Currently Keycloak supports securing your web applications running inside http://www.jboss.org/products/fuse/overview/[JBoss Fuse] or http://karaf.apache.org/[Apache Karaf] . -It leverages <<_jetty8_adapter,Jetty 8 adapter>> as both JBoss Fuse 6.2 and Apache Karaf 3 are bundled with http://eclipse.org/jetty/[Jetty 8.1 server] +Currently {{book.project.name}} supports securing your web applications running inside http://www.jboss.org/products/fuse/overview/[JBoss Fuse] . +It leverages <> as both JBoss Fuse 6.2 are bundled with http://eclipse.org/jetty/[Jetty 8.1 server] under the covers and Jetty is used for running various kinds of web applications. -What is supported for Fuse/Karaf is: +What is supported for Fuse is: -* Security for classic WAR applications deployed on Fuse/Karaf with https://ops4j1.jira.com/wiki/display/ops4j/Pax+Web+Extender+-+War[Pax Web War Extender]. -* Security for servlets deployed on Fuse/Karaf as OSGI services with https://ops4j1.jira.com/wiki/display/ops4j/Pax+Web+Extender+-+Whiteboard[Pax Web Whiteboard Extender]. +* Security for classic WAR applications deployed on Fuse with https://ops4j1.jira.com/wiki/display/ops4j/Pax+Web+Extender+-+War[Pax Web War Extender]. +* Security for servlets deployed on Fuse as OSGI services with https://ops4j1.jira.com/wiki/display/ops4j/Pax+Web+Extender+-+Whiteboard[Pax Web Whiteboard Extender]. * Security for http://camel.apache.org/[Apache Camel] Jetty endpoints running with http://camel.apache.org/jetty.html[Camel Jetty] component. * Security for http://cxf.apache.org/[Apache CXF] endpoints running on their own separate http://cxf.apache.org/docs/jetty-configuration.html[Jetty engine]. * Security for http://cxf.apache.org/[Apache CXF] endpoints running on default engine provided by CXF servlet. @@ -19,84 +19,10 @@ What is supported for Fuse/Karaf is: ==== How to secure your web applications inside Fuse -The best place to start is look at Fuse demo bundled as part of Keycloak examples in directory `fuse` . Most of the steps should be understandable from testing and +Basically all mentioned web applications require to inject {{book.project.name}} Jetty authenticator into underlying Jetty server . The steps to achieve it are bit different +according to application type. The details are described in individual sub-chapters. + +{% if book.community %} +The best place to start is look at Fuse demo bundled as part of {{book.project.name}} examples in directory `fuse` . Most of the steps should be understandable from testing and understanding the demo. - -Basically all mentioned web applications require to inject Keycloak Jetty authenticator into underlying Jetty server . The steps to achieve it are bit different -according to application type. - - -===== Classic WAR application - -The needed steps are: - -* Declare needed constraints in `/WEB-INF/web.xml` -* Add `jetty-web.xml` file with the authenticator to `/WEB-INF/jetty-web.xml` and add `/WEB-INF/keycloak.json` with your Keycloak configuration -* Make sure your WAR imports `org.keycloak.adapters.jetty` and maybe some more packages in MANIFEST.MF file in header `Import-Package`. It's -recommended to use maven-bundle-plugin similarly like Fuse examples are doing, but note that "*" resolution for package doesn't import `org.keycloak.adapters.jetty` package -as it's not used by application or Blueprint or Spring descriptor, but it's used just in jetty-web.xml file. - -Take a look at `customer-portal-app` from fuse example for inspiration. - -===== Servlet web application deployed by pax-whiteboard-extender - -The needed steps are: - -* Keycloak provides PaxWebIntegrationService, which allows to inject jetty-web.xml and configure security constraints for your application. -Example `product-portal-app` declares this in `OSGI-INF/blueprint/blueprint.xml` . Note that your servlet needs to depend on it. -* Steps 2,3 are same like for classic WAR - -Take a look at `product-portal-app` for inspiration. - -===== Apache camel application - -You can secure your Apache camel endpoint using http://camel.apache.org/jetty.html[camel-jetty] endpoint by adding securityHandler with `KeycloakJettyAuthenticator` and -proper security constraints injected. Take a look at `OSGI-INF/blueprint/blueprint.xml` configuration in `camel` application on example of how it can be done in details. - -===== Apache CXF endpoint - -It's recommended to run your CXF endpoints secured by Keycloak on separate Jetty engine. You need to add `META-INF/spring/beans.xml` to your application -and then declare `httpj:engine-factory` with Jetty SecurityHandler with injected `KeycloakJettyAuthenticator` inside. - -Fore more details, take a look at example application `cxf-ws` from Keycloak Fuse demo, which is using separate endpoint on -http://localhost:8282 . All the important configuration inside this application is declared in `META-INF/spring/beans.xml` . - -===== Builtin CXF web applications - -Some services automatically come with deployed servlets on startup. One of such examples is CXF servlet running on -http://localhost:8181/cxf context. Securing such endpoints is quite tricky. The approach, which Keycloak is currently using, -is providing ServletReregistrationService, which undeploys builtin servlet at startup, so you are able to re-deploy it again on context secured by Keycloak. -You can see the `OSGI-INF/blueprint/blueprint.xml` inside `cxf-jaxrs` example, which adds JAX-RS `customerservice` endpoint and more importantly, it secures whole `/cxf` context. - -As a side effect, all other CXF services running on default CXF HTTP destination will be secured too. Once you uninstall feature `keycloak-fuse-6.2-example`, the -original unsecured servlet on `/cxf` context is deployed back and hence context will become unsecured again. - -It's recommended to use your own Jetty engine for your apps (similarly like `cxf-jaxws` application is doing). - - -==== How to secure Fuse admin services - -===== SSH authentication to Fuse terminal with Keycloak credentials - -Keycloak mainly addresses usecases for authentication of web applications, however if your admin services (like fuse admin console) are protected -with Keycloak, it may be good to protect non-web services like SSH with Keycloak credentials too. It's possible to do it by using JAAS login module, which -allows to remotely connect to Keycloak and verify credentials based on <<_direct_access_grants,Direct Access Grants>> . - -Example steps for enable SSH authentication require changing the configuration of `sshRealm` in `$FUSE_HOME/etc/org.apache.karaf.shell.cfg`, then adding -file `$FUSE_HOME/etc/keycloak-direct-access.json` (this is default location, which can be changed) and install the needed feature `keycloak-jaas`. It's described in details -in the README file of Fuse example, which in example distribution is inside `fuse/fuse-admin/README.md` . - - -===== JMX authentication with Keycloak credentials - -This may be needed in case if you really want to use jconsole or other external tool to perform remote connection to JMX through RMI. Otherwise it may -be better to use just hawt.io/jolokia as jolokia agent is installed in http://hawt.io by default. - -You need to configure `jmxRealm` in `$FUSE_HOME/etc/org.apache.karaf.management.cfg`, then adding file `$FUSE_HOME/etc/keycloak-direct-access.json` -(this is default location, which can be changed) and install the needed feature `keycloak-jaas`. -It's described in details in the README file of Fuse example, which in example distribution is inside `fuse/fuse-admin/README.md` . - - -===== Secure Fuse admin console - -Fuse admin console is Hawt.io. See http://hawt.io/configuration/index.html[Hawt.io documentation] for more info about how to secure it with Keycloak. \ No newline at end of file +{% endif %} \ No newline at end of file diff --git a/topics/oidc/java/fuse/camel.adoc b/topics/oidc/java/fuse/camel.adoc new file mode 100644 index 0000000000..b79229de6c --- /dev/null +++ b/topics/oidc/java/fuse/camel.adoc @@ -0,0 +1,95 @@ + +[[_fuse_adapter_camel]] +==== Apache Camel Application + +* You can secure your Apache camel endpoint using http://camel.apache.org/jetty.html[camel-jetty] component by adding securityHandler with `KeycloakJettyAuthenticator` and +proper security constraints injected. You can add file `OSGI-INF/blueprint/blueprint.xml` into your camel application with the configuration similar to below. +The roles, security constraint mappings and {{book.project.name}} adapter configuration may be a bit different according to your environment and needs: + +[source,xml] +---- + + + + + + + + + + + + + + + + + + + + + + admin + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +---- + + +* The `Import-Package` in `META-INF/MANIFEST.MF` needs to contain those imports: +[source] +---- +javax.servlet;version="[3,4)", +javax.servlet.http;version="[3,4)", +org.apache.camel.*, +org.apache.camel;version="[2.13,3)", +org.eclipse.jetty.security;version="[8,10)", +org.eclipse.jetty.server.nio;version="[8,10)", +org.eclipse.jetty.util.security;version="[8,10)", +org.keycloak.*;version="{{book.project.version}}", +org.osgi.service.blueprint, +org.osgi.service.blueprint.container, +org.osgi.service.event, +---- + diff --git a/topics/oidc/java/fuse/classic-war.adoc b/topics/oidc/java/fuse/classic-war.adoc new file mode 100644 index 0000000000..7ff0bfc98e --- /dev/null +++ b/topics/oidc/java/fuse/classic-war.adoc @@ -0,0 +1,82 @@ + +[[_fuse_adapter_classic_war]] +==== Secure Classic WAR application + +The needed steps to secure your WAR are: + +* Declare needed security constraints in `/WEB-INF/web.xml` . You also need to declare login-config and all the roles inside security-role. +The example configuration can look like this: + +[source,xml] +---- + + + + customer-portal + + + index.html + + + + + Customers + /customers/* + + + user + + + + + BASIC + does-not-matter + + + + admin + + + user + + +---- + +* Add `jetty-web.xml` file with the authenticator to `/WEB-INF/jetty-web.xml` . Typically it will look like this: + +[source,xml] +---- + + + + + + + + + + +---- + +* Add `/WEB-INF/keycloak.json` with your {{book.project.name}} configuration. The format of this config file is described +in the <> section. + +* Make sure your WAR imports `org.keycloak.adapters.jetty` and maybe some more packages in `META-INF/MANIFEST.MF` file in header `Import-Package`. It's +recommended to use `maven-bundle-plugin` in your project to properly generate OSGI headers in manifest. +Note that "*" resolution for package doesn't import `org.keycloak.adapters.jetty` package +as it's not used by application or Blueprint or Spring descriptor, but it's used just in `jetty-web.xml` file. So list of the packages to import may look like this: + +[source] +---- +org.keycloak.adapters.jetty;version="{{book.project.version}}", +org.keycloak.adapters;version="{{book.project.version}}", +org.keycloak.constants;version="{{book.project.version}}", +org.keycloak.util;version="{{book.project.version}}", +org.keycloak.*;version="{{book.project.version}}", +*;resolution:=optional +---- + diff --git a/topics/oidc/java/fuse/cxf-builtin.adoc b/topics/oidc/java/fuse/cxf-builtin.adoc new file mode 100644 index 0000000000..ff4211a8c5 --- /dev/null +++ b/topics/oidc/java/fuse/cxf-builtin.adoc @@ -0,0 +1,98 @@ + +[[_fuse_adapter_cxf_builtin]] +==== Secure Apache CXF Endpoint on default Jetty Engine + +Some services automatically come with deployed servlets on startup. One of such services is CXF servlet running on +http://localhost:8181/cxf context. Securing such endpoints is quite tricky. The approach, which {{book.project.name}} is currently using, +is providing ServletReregistrationService, which undeploys builtin servlet at startup, so you are able to re-deploy it again on context secured by {{book.project.name}}. +This is how configuration file `OSGI-INF/blueprint/blueprint.xml` inside your application may look like. Note it adds JAX-RS `customerservice` endpoint, +which is endpoint specific to your application, but more importantly, it secures whole `/cxf` context. + +[source,xml] +---- + + + + + + + + + + + + + + + + + + + + + + + + + + user + + + + + + + + + + + + + + + + + + + + + + + + + + + +---- + +As a side effect, all other CXF services running on default CXF HTTP destination will be secured too. Similarly when the application is undeployed, then +whole `/cxf` context will become unsecured too. For this reason, it's recommended to use your own Jetty engine for your apps like +described in <> as then you have more +control over security for each application individually. + +* You may need to have directory `WEB-INF` inside your project (even if your project is not web application) and create files `/WEB-INF/jetty-web.xml` and + `/WEB-INF/keycloak.json` in similar way like it's in <>. + Note you don't need `web.xml` as the security-constrains are declared in blueprint configuration file. + + +* The `Import-Package` in `META-INF/MANIFEST.MF` needs to contain those imports: +[source] +---- +META-INF.cxf;version="[2.7,3.2)", +META-INF.cxf.osgi;version="[2.7,3.2)";resolution:=optional, +org.apache.cxf.transport.http;version="[2.7,3.2)", +org.apache.cxf.*;version="[2.7,3.2)", +com.fasterxml.jackson.jaxrs.json;version="[2.5,3)", +org.eclipse.jetty.security;version="[8,10)", +org.eclipse.jetty.util.security;version="[8,10)", +org.keycloak.*;version="{{book.project.version}}", +org.keycloak.adapters.jetty;version="{{book.project.version}}", +*;resolution:=optional +---- diff --git a/topics/oidc/java/fuse/cxf-separate.adoc b/topics/oidc/java/fuse/cxf-separate.adoc new file mode 100644 index 0000000000..86e12b76a1 --- /dev/null +++ b/topics/oidc/java/fuse/cxf-separate.adoc @@ -0,0 +1,111 @@ + +[[_fuse_adapter_cxf_separate]] +==== Secure Apache CXF Endpoint on separate Jetty + +It's recommended to run your CXF endpoints secured by {{book.project.name}} on separate Jetty engine. This is the setup described in this section. + +* You need to add `META-INF/spring/beans.xml` to your application and then declare `httpj:engine-factory` with Jetty SecurityHandler with +injected `KeycloakJettyAuthenticator` inside. The configuration may look like this for CXF JAX-WS application: + +[source,xml] +---- + + + + + + + + + + + + + + + + + + + + + + + + + + user + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + + + + +---- + +* For the CXF JAX-RS application, the only difference might be in the configuration of the endpoint dependent on engine-factory: + +[source,xml] +---- + + + + + +---- + + +* The `Import-Package` in `META-INF/MANIFEST.MF` needs to contain those imports: +[source] +---- +META-INF.cxf;version="[2.7,3.2)", +META-INF.cxf.osgi;version="[2.7,3.2)";resolution:=optional, +org.apache.cxf.bus;version="[2.7,3.2)", +org.apache.cxf.bus.spring;version="[2.7,3.2)", +org.apache.cxf.bus.resource;version="[2.7,3.2)", +org.apache.cxf.transport.http;version="[2.7,3.2)", +org.apache.cxf.*;version="[2.7,3.2)", +org.springframework.beans.factory.config, +org.eclipse.jetty.security;version="[8,10)", +org.eclipse.jetty.util.security;version="[8,10)", +org.keycloak.*;version="{{book.project.version}}" +---- \ No newline at end of file diff --git a/topics/oidc/java/fuse/fuse-admin.adoc b/topics/oidc/java/fuse/fuse-admin.adoc new file mode 100644 index 0000000000..33223d587a --- /dev/null +++ b/topics/oidc/java/fuse/fuse-admin.adoc @@ -0,0 +1,87 @@ + +[[_fuse_adapter_admin]] +==== Secure Fuse Admin Services + +===== SSH authentication to Fuse terminal + +{{book.project.name}} mainly addresses usecases for authentication of web applications, however if your other web services and applications are protected +with {{book.project.name}}, it may be good to protect non-web admin services like SSH with {{book.project.name}} credentials too. It's possible to do it +by using JAAS login module, which allows to remotely connect to {{book.project.name}} and verify credentials based on +<> . + +Example steps for enable SSH authentication: + +* In {{book.project.name}} you need to create client (assume it's called `ssh-jmx-admin-client`), which will be used for SSH authentication. +This client needs to have switch `Direct grant enabled` to true. + +* You need to update/specify this property in file `$FUSE_HOME/etc/org.apache.karaf.shell.cfg`: + +[source] +---- +sshRealm=keycloak +---- + +* Add file `$FUSE_HOME/etc/keycloak-direct-access.json` with the content similar to this (change based on your environment and {{book.project.name}} client settings): +[source,json] +---- +{ + "realm": "demo", + "resource": "ssh-jmx-admin-client", + "realm-public-key": "MIGfMA...", + "ssl-required" : "external", + "auth-server-url" : "http://localhost:8080/auth", + "credentials": { + "secret": "password" + } +} +---- +This file contains configuration of the client application, which is used by JAAS DirectAccessGrantsLoginModule from `keycloak` JAAS realm for SSH authentication. + +* Start Fuse and install `keycloak` JAAS realm into Fuse. This could be done easily by installing `keycloak-jaas` feature, which has JAAS realm predefined +(you are able to override it by using your own `keycloak` JAAS realm with higher ranking). Use those commands in Fuse terminal: + +``` +features:addurl mvn:org.keycloak/keycloak-osgi-features/{{book.project.version}}/xml/features +features:install keycloak-jaas +``` + +* Now let's type this from your terminal to login via SSH as `admin` user: + +``` +ssh -o PubkeyAuthentication=no -p 8101 admin@localhost +``` + +And login with password `password` . Note that your user needs to have realm role `admin` . The required roles are configured in `$FUSE_HOME/etc/org.apache.karaf.shell.cfg` + + +===== JMX authentication + +This may be needed in case if you really want to use jconsole or other external tool to perform remote connection to JMX through RMI. Otherwise it may +be better to use just hawt.io/jolokia as jolokia agent is installed in hawt.io by default. + +* In file `$FUSE_HOME/etc/org.apache.karaf.management.cfg` you can change this property: + +[source] +---- +jmxRealm=keycloak +---- + +* You need `keycloak-jaas` feature and file `$FUSE_HOME/etc/keycloak-direct-access.json` as described in SSH section above. + +* In jconsole you can fill URL like: + +[source] +---- +service:jmx:rmi://localhost:44444/jndi/rmi://localhost:1099/karaf-root +---- + +and credentials: admin/password (based on the user with admin privileges according to your environment) + +Note again that users without `admin` role are not able to login as they are not authorized. However users with access to Hawt.io admin console +may be still able to access MBeans remotely via HTTP (Hawtio). So make sure to protect Hawt.io web console with same roles like JMX through RMI to +really protect JMX mbeans. + + +===== Secure Fuse admin console + +Fuse admin console is Hawt.io. See http://hawt.io/configuration/index.html[Hawt.io documentation] for more info about how to secure it with {{book.project.name}}. \ No newline at end of file diff --git a/topics/oidc/java/fuse/servlet-whiteboard.adoc b/topics/oidc/java/fuse/servlet-whiteboard.adoc new file mode 100644 index 0000000000..37c0893803 --- /dev/null +++ b/topics/oidc/java/fuse/servlet-whiteboard.adoc @@ -0,0 +1,76 @@ + +[[_fuse_adapter_servlet_whiteboard]] +==== Secure Servlet deployed as OSGI service + +This is useful for the case, when you have sevlet class inside your OSGI bundle project, which is not deployed as classic WAR. Fuse uses +https://ops4j1.jira.com/wiki/display/ops4j/Pax+Web+Extender+-+Whiteboard[Pax Web Whiteboard Extender] for deploy such servlet as web application. + +The needed steps to secure your servlet with {{book.project.name}} are: + +* Keycloak provides PaxWebIntegrationService, which allows to inject jetty-web.xml and configure security constraints for your application. + You need to declare such service in `OSGI-INF/blueprint/blueprint.xml` inside your application. Note that your servlet needs to depend on it. + The example configuration can look like this: +[source,xml] +---- + + + + + + + + + + + user + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +---- + +* You may need to have directory `WEB-INF` inside your project (even if your project is not web application) and create files `/WEB-INF/jetty-web.xml` and +`/WEB-INF/keycloak.json` in similar way like it's in <>. +Note you don't need `web.xml` as the security-constrains are declared in blueprint configuration file. + +* The `Import-Package` in `META-INF/MANIFEST.MF` needs to contain at least those imports: +[source] +---- +org.keycloak.adapters.jetty;version="{{book.project.version}}", +org.keycloak.adapters;version="{{book.project.version}}", +org.keycloak.constants;version="{{book.project.version}}", +org.keycloak.util;version="{{book.project.version}}", +org.keycloak.*;version="{{book.project.version}}", +*;resolution:=optional +---- From e9241f8c1dd86bf8a59edfe515694b01e74caa1e Mon Sep 17 00:00:00 2001 From: Thomas Darimont Date: Mon, 6 Jun 2016 10:22:23 +0200 Subject: [PATCH 3/5] Fix #11: Document integration with Apache module mod_auth_openidc --- SUMMARY.adoc | 1 + topics/oidc/mod-auth-openidc.adoc | 49 +++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 topics/oidc/mod-auth-openidc.adoc diff --git a/SUMMARY.adoc b/SUMMARY.adoc index 1ef570a8d9..d230ec7d6b 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -35,6 +35,7 @@ .. link:topics/oidc/javascript-adapter.adoc[JavaScript Adapter] .. link:topics/oidc/oidc-generic.adoc[Other OpenID Connect libraries] + ... link:topics/oidc/mod-auth-openidc.adoc[mod_auth_oidc Apache HTTPD Module] . link:topics/saml/saml-overview.adoc[SAML] .. link:topics/saml/java/java-adapters.adoc[Java Adapters] diff --git a/topics/oidc/mod-auth-openidc.adoc b/topics/oidc/mod-auth-openidc.adoc new file mode 100644 index 0000000000..25e03be59a --- /dev/null +++ b/topics/oidc/mod-auth-openidc.adoc @@ -0,0 +1,49 @@ +[[_mod_auth_openidc]] +=== mod_auth_openidc Apache HTTPD Module + +The https://github.com/pingidentity/mod_auth_openidc[mod_auth_openidc] is an Apache HTTP plugin for OpenID Connect. If your language/environment supports using Apache HTTPD +as a proxy, then you can use _mod_auth_openidc_ to secure your web application with OpenID Connect. Configuration of this module +is beyond the scope of this document. Please see the _mod_auth_openidc_ Github repo for more details on configuration. + +To configure _mod_auth_openidc_ you'll need + +* The client_id. +* The client_secret. +* The redirect_uri to your application. +* The Keycloak openid-configuration url +* _mod_auth_openidc_ specific Apache HTTPD module config. + +An example configuration would look like the following. + +[source,xml] +---- +LoadModule auth_openidc_module modules/mod_auth_openidc.so + +ServerName ${HOSTIP} + + + + ServerAdmin webmaster@localhost + DocumentRoot /var/www/html + + #this is required by mod_auth_openidc + OIDCCryptoPassphrase a-random-secret-used-by-apache-oidc-and-balancer + + OIDCProviderMetadataURL ${KC_ADDR}/auth/realms/${KC_REALM}/.well-known/openid-configuration + + OIDCClientID ${CLIENT_ID} + OIDCClientSecret ${CLIENT_SECRET} + OIDCRedirectURI http://${HOSTIP}/${CLIENT_APP_NAME}/redirect_uri + + # maps the prefered_username claim to the REMOTE_USER environment variable + OIDCRemoteUserClaim preferred_username + + + AuthType openid-connect + Require valid-user + + +---- + +Further information on how to configure mod_auth_openidc can be found on the https://github.com/pingidentity/mod_auth_openidc[mod_auth_openidc] +project page. \ No newline at end of file From d16bf618465415989e0e12c539bdd426e3994b90 Mon Sep 17 00:00:00 2001 From: Stian Thorgersen Date: Mon, 6 Jun 2016 11:00:44 +0200 Subject: [PATCH 4/5] Added generic OIDC chapter --- topics/client-registration.adoc | 1 + topics/oidc/oidc-generic.adoc | 175 +++++++++++++++++++++++++++----- 2 files changed, 152 insertions(+), 24 deletions(-) diff --git a/topics/client-registration.adoc b/topics/client-registration.adoc index 304436ebd3..cd28d31058 100644 --- a/topics/client-registration.adoc +++ b/topics/client-registration.adoc @@ -1,3 +1,4 @@ +[[_client_registration]] == Client Registration In order for an application or service to utilize {{book.project.name}} it has to register a client in {{book.project.name}}. diff --git a/topics/oidc/oidc-generic.adoc b/topics/oidc/oidc-generic.adoc index d625f9a539..4c71cdade3 100644 --- a/topics/oidc/oidc-generic.adoc +++ b/topics/oidc/oidc-generic.adoc @@ -1,47 +1,174 @@ == Other OpenID Connect libraries -OAuth2 https://tools.ietf.org/html/rfc6749 -OpenID Connect http://openid.net/connect/ - +{{book.project.name}} can be secured by supplied adapters that usually are easier to use and provide better integration with {{book.project.name}}. However, +if there is no adapter available for your programming language, framework or platform you may opt to use a generic OpenID Connect Resource Provider (RP) library +instead. This chapter describes details specific to {{book.project.name}} and doesn't go into low-level details of the protocols. For more details refer to the +http://openid.net/connect/[OpenID Connect specifications] and https://tools.ietf.org/html/rfc6749[OAuth2 specification]. === Endpoints -TODO +The most important endpoint to know is the `well-known` configuration endpoint. It lists endpoints and other configuration options relevant to the OpenID +Connect implementation in {{book.project.name}}. The endpoint is: + +.... +/realms/REALM-NAME/.well-known/openid-configuration +.... + +To get the full URL add the base URL for {{book.project.name}} and replace `REALM-NAME` with the name of your realm. For example: + +http://localhost:8080/auth/realms/master/.well-known/openid-configuration + +Some RP libraries will retrieve all required endpoints from this endpoint, but for others you may need to list the endpoints individually. + +==== Authorization Endpoint +.... +/realms/master/protocol/openid-connect/auth +.... + +Performs authentication of the end-user. This is done by redirecting user agent to this endpoint. + +For more details see http://openid.net/specs/openid-connect-core-1_0.html#AuthorizationEndpoint[Authorization Endpoint] section in OpenID Connect specification. + +==== Token Endpoint +.... +/realms/master/protocol/openid-connect/token +.... + +Used to obtain tokens. Tokens can either be obtained by exchanging an authorization code or by supplying credentials directly depending on what flow is used. +The token endpoint is also used to obtain new access tokens when they expire. + +For more details see http://openid.net/specs/openid-connect-core-1_0.html#TokenEndpoint[Token Endpoint] section in OpenID Connect specification. + +==== Userinfo Endpoint +.... +/realms/master/protocol/openid-connect/userinfo +.... + +Returns standard claims about the authenticated user. Protected by a bearer token. + +For more details see http://openid.net/specs/openid-connect-core-1_0.html#UserInfo[Userinfo Endpoint] section in OpenID Connect specification. + +==== Logout Endpoint +.... +/realms/master/protocol/openid-connect/logout +.... + +Logs out the authenticated user. + +User agent can be redirected to the endpoint in which case the active user session will be logged out. Afterwards the user agent is redirected back to the application. + +The endpoint can also be invoked directly by the application. To invoke this endpoint directly the refresh token needs to be included as well as credentials +required to authenticate the client. + +==== Certificate Endpoint +.... +/realms/master/protocol/openid-connect/certs +.... + +Public key used by realm encoded as a JSON Web Key (JWK). This key can be used to verify tokens issued by {{book.project.name}} without making invocations to +the server. + +For more details see https://tools.ietf.org/html/rfc7517[JSON Web Key specification]. + +==== Introspection Endpoint +.... +/realms/master/protocol/openid-connect/token/introspect +.... + +Used to retrieve the active state of a token. Protected by a bearer token and can only be invoked by confidential clients. + +For more details see https://tools.ietf.org/html/rfc7662[OAuth 2.0 Token Introspection specification]. + +==== Dynamic Client Registration Endpoint +.... +/realms/master/clients-registrations/openid-connect +.... + +Used to dynamically register clients. + +For more details see <> and the +https://openid.net/specs/openid-connect-registration-1_0.html[OpenID Connect Dynamic Client Registration specification]. + === Flows -==== Authorization Grant +==== Authorization Code + +The Authorization Code flow redirects the user agent to {{book.project.name}}. Once the user has successfully authenticated with {{book.project.name}} an +Authorization Code is created and the user agent is redirected back to the application. The application then uses the authorization code to along with its +credentials to obtain an Access Roken, Refresh Token and ID Token from {{book.project.name}}. + +The flow is targeted towards web applications, but is also recommended for native applications, including mobile applications, where it is possible to embed +a user agent. + +For more details refer to the http://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth[Authorization Code Flow] in the OpenID Connect specification. ==== Implicit -[[_resource_owner_password_credentials_flow]] +The Implicit flow redirects works similarly to the Authorization Code flow, but instead of returning a Authorization Code the Access Token and ID Token is +returned. This reduces the need for the extra invocation to exchange the Authorization Code for an Access Token. However, it does not include a Refresh +Token. This results in the need to either permit Access Tokens with a long expiration, which is problematic as it's very hard to invalidate these. Or +requires a new redirect to obtain new Access Token once the initial Access Token has expired. The Implicit flow is useful if the application only wants to +authenticate the user and deals with logout itself. + +There's also a Hybrid flow where both the Access Token and an Authorization Code is returned. + +One thing to note is that both the Implicit flow and Hybrid flow has potential security risks as the Access Token may be leaked through web server logs and +browser history. This is somewhat mitigated by using short expiration for Access Tokens. + +For more details refer to the http://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowAuth[Implicit Flow] in the OpenID Connect specification. + ==== Resource Owner Password Credentials +Resource Owner Password Credentials, referred to as Direct Grant in {{book.project.name}}, allows exchanging user credentials for tokens. It's not recommended +to use this flow unless you absolutely need to. Examples where this could be useful are legacy applications and command-line interfaces. + +There are a number of limitations of using this flow, including: + +* User credentials are exposed to the application +* Applications need login pages +* Application needs to be aware of the authentication scheme +* Changes to authentication flow requires changes to application +* No support for identity brokering or social login +* Flows are not supported (user self-registration, required actions, etc.) + +This flow is not included in OpenID Connect, but is a part of the OAuth 2.0 specification. + +For more details refer to the https://tools.ietf.org/html/rfc6749#section-4.3[Resource Owner Password Credentials Grant] chapter in the OAuth 2.0 specification. + ==== Client Credentials +Client Credentials is used when clients (applications and services) wants to obtain access on behalf of themselves rather than on behalf of a user. This can +for example be useful for background services that applies changes to the system in general rather than for a specific user. + +{{book.project.name}} provides support for clients to authenticate either with a secret or with public/private keys. + +This flow is not included in OpenID Connect, but is a part of the OAuth 2.0 specification. + +For more details refer to the https://tools.ietf.org/html/rfc6749#section-4.4[Client Credentials Grant] chapter in the OAuth 2.0 specification. + === Redirect URIs -Keycloak provides two special redirect uris for installed applications. +When using the redirect based flows it's important to use valid redirect uris for your clients. The redirect uris should be as specific as possible. This +especially applies to client-side (public clients) applications. Failing to do so could result in: + +* Open redirects - this can allow attackers to create spoof links that looks like they are coming from your domain +* Unauthorized entry - when users are already authenticated with {{book.project.name}} an attacker can use a public client where redirect uris have not be configured correctly to gain access by redirecting the user without the users knowledge + +In production for web applications always use `https` for all redirect URIs. Do not allow redirects to http. + +There's also a few special redirect URIs: [[_installed_applications_url]] -==== Installed Applications url +`http://localhost`:: -http://localhost - -This returns the code to a web server on the client as a query parameter. -Any port number is allowed. -This makes it possible to start a web server for the installed application on any free port number without requiring changes in the `Admin Console`. + This redirect URI is useful for native applications and allows the native application to create a web server on a random port that can be used to obtain the + authorization code. This redirect uri allows any port. [[_installed_applications_urn]] -==== Installed Applications urn +`urn:ietf:wg:oauth:2.0:oob`:: -`urn:ietf:wg:oauth:2.0:oob` - -If its not possible to start a web server in the client (or a browser is not available) it is possible to use the special `urn:ietf:wg:oauth:2.0:oob` redirect uri. -When this redirect uri is used Keycloak displays a page with the code in the title and in a box on the page. -The application can either detect that the browser title has changed, or the user can copy/paste the code manually to the application. -With this redirect uri it is also possible for a user to use a different device to obtain a code to paste back to the application. - -=== Session Management - -=== Dynamic Client Registration \ No newline at end of file + If its not possible to start a web server in the client (or a browser is not available) it is possible to use the special `urn:ietf:wg:oauth:2.0:oob` redirect uri. + When this redirect uri is used Keycloak displays a page with the code in the title and in a box on the page. + The application can either detect that the browser title has changed, or the user can copy/paste the code manually to the application. + With this redirect uri it is also possible for a user to use a different device to obtain a code to paste back to the application. \ No newline at end of file From 3784f8423bc00f9607cc03f5eff6004bb968b95e Mon Sep 17 00:00:00 2001 From: Stian Thorgersen Date: Mon, 6 Jun 2016 11:03:21 +0200 Subject: [PATCH 5/5] Remove mod_auth_openidc in prod docs --- SUMMARY.adoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SUMMARY.adoc b/SUMMARY.adoc index d230ec7d6b..f5ed52c0e0 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -35,7 +35,9 @@ .. link:topics/oidc/javascript-adapter.adoc[JavaScript Adapter] .. link:topics/oidc/oidc-generic.adoc[Other OpenID Connect libraries] + {% if book.community %} ... link:topics/oidc/mod-auth-openidc.adoc[mod_auth_oidc Apache HTTPD Module] + {% endif %} . link:topics/saml/saml-overview.adoc[SAML] .. link:topics/saml/java/java-adapters.adoc[Java Adapters]