kanidm/docs/oauth2.html
2021-10-26 03:18:11 +00:00

286 lines
19 KiB
HTML

<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js light">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Oauth2 - Kanidm Administration</title>
<!-- Custom HTML head -->
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff" />
<link rel="icon" href="favicon.svg">
<link rel="shortcut icon" href="favicon.png">
<link rel="stylesheet" href="css/variables.css">
<link rel="stylesheet" href="css/general.css">
<link rel="stylesheet" href="css/chrome.css">
<link rel="stylesheet" href="css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="highlight.css">
<link rel="stylesheet" href="tomorrow-night.css">
<link rel="stylesheet" href="ayu-highlight.css">
<!-- Custom theme stylesheets -->
</head>
<body>
<!-- Provide site root to javascript -->
<script type="text/javascript">
var path_to_root = "";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script type="text/javascript">
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script type="text/javascript">
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('no-js')
html.classList.remove('light')
html.classList.add(theme);
html.classList.add('js');
</script>
<!-- Hide / unhide sidebar before it is displayed -->
<script type="text/javascript">
var html = document.querySelector('html');
var sidebar = 'hidden';
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
}
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox">
<ol class="chapter"><li class="chapter-item expanded "><a href="intro.html"><strong aria-hidden="true">1.</strong> Introduction to Kanidm</a></li><li class="chapter-item expanded "><a href="installing_the_server.html"><strong aria-hidden="true">2.</strong> Installing the Server</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="server_configuration.html"><strong aria-hidden="true">2.1.</strong> Server Configuration</a></li><li class="chapter-item expanded "><a href="security_hardening.html"><strong aria-hidden="true">2.2.</strong> Security Hardening</a></li></ol></li><li class="chapter-item expanded "><a href="client_tools.html"><strong aria-hidden="true">3.</strong> Client Tools</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="installing_client_tools.html"><strong aria-hidden="true">3.1.</strong> Installing client tools</a></li></ol></li><li class="chapter-item expanded "><a href="accounts_and_groups.html"><strong aria-hidden="true">4.</strong> Accounts and Groups</a></li><li class="chapter-item expanded "><a href="administrivia.html"><strong aria-hidden="true">5.</strong> Administrative Tasks</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="monitoring.html"><strong aria-hidden="true">5.1.</strong> Monitoring the platform</a></li><li class="chapter-item expanded "><a href="password_quality.html"><strong aria-hidden="true">5.2.</strong> Password Quality and Badlisting</a></li><li class="chapter-item expanded "><a href="posix_accounts.html"><strong aria-hidden="true">5.3.</strong> POSIX Accounts and Groups</a></li><li class="chapter-item expanded "><a href="ssh_key_dist.html"><strong aria-hidden="true">5.4.</strong> SSH Key Distribution</a></li><li class="chapter-item expanded "><a href="recycle_bin.html"><strong aria-hidden="true">5.5.</strong> The Recycle Bin</a></li></ol></li><li class="chapter-item expanded "><a href="oauth2.html" class="active"><strong aria-hidden="true">6.</strong> Oauth2</a></li><li class="chapter-item expanded "><a href="pam_and_nsswitch.html"><strong aria-hidden="true">7.</strong> PAM and nsswitch</a></li><li class="chapter-item expanded "><a href="radius.html"><strong aria-hidden="true">8.</strong> RADIUS</a></li><li class="chapter-item expanded "><a href="ldap.html"><strong aria-hidden="true">9.</strong> LDAP</a></li><li class="chapter-item expanded "><a href="why_tls.html"><strong aria-hidden="true">10.</strong> Why TLS?</a></li><li class="chapter-item expanded "><a href="DEVELOPER_README.html"><strong aria-hidden="true">11.</strong> Developer Guide</a></li></ol>
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky bordered">
<div class="left-buttons">
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</button>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Kanidm Administration</h1>
<div class="right-buttons">
<a href="print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script type="text/javascript">
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="oauth2"><a class="header" href="#oauth2">Oauth2</a></h1>
<p>Oauth is a web authorisation protocol that allows &quot;single sign on&quot;. It's key to note
oauth is authorisation, not authentication, as the protocol in it's default forms
do not provide identity or authentication information, only information that
an entity is authorised for the requested resources.</p>
<p>Oauth can tie into extensions allowing an identity provider to reveal information
about authorised sessions. This extends oauth from an authorisation only system
to a system capable of identity and authorisation. Two primary methods of this
exist today: rfc7662 token introspection, and openid connect.</p>
<h2 id="how-does-oauth2-work"><a class="header" href="#how-does-oauth2-work">How Does Oauth2 Work?</a></h2>
<p>A user wishes to access a service (resource, resource server). The resource
server does not have an active session for the client, so it redirects to the
authorisation server (Kanidm) to determine if the client should be allowed to proceed, and
has the appropriate permissions (scopes) for the requested resources.</p>
<p>The authorisation server checks the current session of the user and may present
a login flow if required. Given the identity of the user known to the authorisation
sever, and the requested scopes, the authorisation server makes a decision if it
allows the authorisation to proceed. The user is then prompted to consent to the
authorisation from the authorisation server to the resource server as some identity
information may be revealed by granting this consent.</p>
<p>If successful and consent given, the user is redirected back to the resource server with an authorisation
code. The resource server then contacts the authorisation server directly with this
code and exchanges it for a valid token that may be provided to the users browser.</p>
<p>The resource server may then optionally contact the token introspection endpoint of the authorisation server about the
provided oauth token, which yields extra metadata about the identity that holds the
token from the authorisation. This metadata may include identity information,
but also may include extended metadata, sometimes refered to as &quot;claims&quot;. Claims are
information bound to a token based on properties of the session that may allow
the resource server to make extended authorisation decisions without the need
to contact the authorisation server to arbitrate.</p>
<p>It's important to note that oauth2 at it's core is an authorisation system which has layered
identity providing elements on top.</p>
<h3 id="resource-server"><a class="header" href="#resource-server">Resource Server</a></h3>
<p>This is the server that a user wants to access. Common examples could be nextcloud, a wiki
or something else. This is the system that &quot;needs protecting&quot; and wants to delegate authorisation
decisions to Kanidm.</p>
<p>It's important for you to know <em>how</em> your resource server supports oauth2. For example, does it
support rfc7662 token introspection or does it rely on openid connect for identity information?
Does the resource server support PKCE S256 or not?</p>
<blockquote>
<p>Note: OpenID Connect (OIDC) is not currently supported at this time - if you're interested in finding out when it's ready, please follow <a href="https://github.com/kanidm/kanidm/issues/278">Issue #278</a></p>
</blockquote>
<p>In general Kanidm requires that your resource server supports:</p>
<ul>
<li>HTTP basic authentication to the authorisation server</li>
<li>PKCE S256 code verification to prevent certain token attack classes</li>
</ul>
<p>Kanidm will expose it's oauth2 apis at the urls:</p>
<ul>
<li>auth url: https://idm.example.com/ui/oauth2</li>
<li>token url: https://idm.example.com/oauth2/token</li>
<li>token inspect url: https://idm.example.com/oauth2/inspect</li>
</ul>
<h3 id="scope-relationships"><a class="header" href="#scope-relationships">Scope Relationships</a></h3>
<p>For an authorisation to proceed, the resource server will request a list of scopes, which are
unique to that resource server. For example, when a user wishes to login to the admin panel
of the resource server, it may request the &quot;admin&quot; scope from kanidm for authorisation. But when
a user wants to login, it may only request &quot;access&quot; as a scope from kanidm.</p>
<p>As each resource server may have it's own scopes and understanding of these, Kanidm isolates
scopes to each resource server connected to Kanidm. Kanidm has two methods of granting scopes to accounts (users).</p>
<p>The first are implicit scopes. These are scopes granted to all accounts that Kanidm holds.</p>
<p>The second is scope mappings. These provide a set of scopes if a user is a member of a specific
group within Kanidm. This allows you to create a relationship between the scopes of a resource
server, and the groups/roles in Kanidm which can be specific to that resource server.</p>
<p>For an authorisation to proceed, all scopes requested must be available in the final scope set
that is granted to the account. This final scope set can be built from implicit and mapped
scopes.</p>
<h2 id="configuration"><a class="header" href="#configuration">Configuration</a></h2>
<h3 id="create-the-kanidm-configuration"><a class="header" href="#create-the-kanidm-configuration">Create the Kanidm Configuration</a></h3>
<p>After you have understood your resource server requirements you first need to configure Kanidm.
By default members of &quot;system_admins&quot; or &quot;idm_hp_oauth2_manage_priv&quot; are able to create or
manage oauth2 resource server integrations.</p>
<p>You can create a new resource server with:</p>
<pre><code>kanidm system oauth2 create &lt;name&gt; &lt;displayname&gt; &lt;origin&gt;
kanidm system oauth2 create nextcloud &quot;Nextcloud Production&quot; https://nextcloud.example.com
</code></pre>
<p>If you wish to create implicit scopes you can set these with:</p>
<pre><code>kanidm system oauth2 set_implicit_scopes &lt;name&gt; [scopes]...
kanidm system oauth2 set_implicit_scopes nextcloud login read_user
</code></pre>
<p>You can create a scope map with:</p>
<pre><code>kanidm system oauth2 create_scope_map &lt;name&gt; &lt;kanidm_group_name&gt; [scopes]...
kanidm system oauth2 create_scope_map nextcloud nextcloud_admins admin
</code></pre>
<p>Once created you can view the details of the resource server.</p>
<pre><code>kanidm system oauth2 get nextcloud
---
class: oauth2_resource_server
class: oauth2_resource_server_basic
class: object
displayname: Nextcloud Production
oauth2_rs_basic_secret: &lt;secret&gt;
oauth2_rs_name: nextcloud
oauth2_rs_origin: https://nextcloud.example.com
oauth2_rs_token_key: hidden
</code></pre>
<h3 id="configure-the-resource-server"><a class="header" href="#configure-the-resource-server">Configure the Resource Server</a></h3>
<p>On your resource server, you should configure the client id as the &quot;oauth2_rs_name&quot; from
kanidm, and the password to be the value shown in &quot;oauth2_rs_basic_secret&quot;. Ensure that
the code challenge/verification method is set to S256.</p>
<p>You should now be able to test authorisation.</p>
<h2 id="resetting-resource-server-security-material"><a class="header" href="#resetting-resource-server-security-material">Resetting Resource Server Security Material</a></h2>
<p>In the case of disclosure of the basic secret, or some other security event where you may wish
to invalidate a resource servers active sessions/tokens, you can reset the secret material of
the server with:</p>
<pre><code>kanidm system oauth2 reset_secrets
</code></pre>
<p>Each resource server has unique signing keys and access secrets, so this is limited to each
resource server.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="recycle_bin.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next" href="pam_and_nsswitch.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="recycle_bin.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next" href="pam_and_nsswitch.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script type="text/javascript">
window.playground_copyable = true;
</script>
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
<script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
<script src="searcher.js" type="text/javascript" charset="utf-8"></script>
<script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
<script src="highlight.js" type="text/javascript" charset="utf-8"></script>
<script src="book.js" type="text/javascript" charset="utf-8"></script>
<!-- Custom JS scripts -->
</body>
</html>