<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Fri, Mar 8, 2013 at 11:07 PM, Toshio Kuratomi <span dir="ltr"><<a href="mailto:a.badger@gmail.com" target="_blank">a.badger@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">So in the past week a bunch of us have been talking about API Keys, OAuth,<br>
passwords, and other means of managing authn and authz in the web apps that<br>
are up and coming (specifically mentioned were copr and datagrepper).<br>
Puiterwijk has put in some time reading the OAuth specifications and on<br>
Friday he walked me through how OAuth is supposed to work. I'll give a<br>
summary of his talkl here and then we can kick off some discussion.<br>
<br>
OAuth is a standardized method for a user to grant access to resources that<br>
they own to people and things that are not themselves. Currently this is being<br>
used to allow a user to control the access to data and actions that may be<br>
performed on one web service by another web service. The concepts and<br>
mechanisms can be used in any situation where the user wants to limit what the<br>
software they are using can do on their behalf.<br>
<br>
= Part I: What is OAuth? =<br><br></blockquote><div style><snip> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
== Flow of a basic request from start to finish ==<br>
<br>
* The client program needs to get access to a protected resource.<br>
* The client asks the authorization server for a client-id and tells the server<br>
which permissions it needs<br>
* The authrization server gives a url to the client<br>
* The client program redirects the user to that url so the user can grant<br>
permissions to the client<br>
* The authorization server authenticates the user (ie: they login to the<br>
authorization server).<br>
* The authorization server asks the user to confirm they want to grant the<br>
requested permissions to the client.<br>
* If the answer is no, the protocol ends.<br>
* If he answer is yes, the user is redirected to the client with an<br>
`authorization code` in the request<br>
* The client sends the `authorization code` to the authorization server.<br>
* The authorization server generates an `access token` with the specific<br>
permissions that the client requested, expires the `authorization code`, and<br>
returns the `access token` to the client,<br>
* The client requests the protected resource from the resource server using the<br>
`access token`.<br>
* The resource server verifes that the `access token` is valid. If it is, it<br>
allows access<br>
<br>
.. note:: the `authorization code` is only good for retrieving a single<br>
`access token` for the particular set of permissions that the user<br>
confirmed.<br>
<br>
.. note:: A client can request access to multiple resources at once. Assuming<br>
the resource owner accepted all of them, the access token the client<br>
receives at the end will allow access to all of those. A client typically<br>
has one access token from an authorization server that grants it all needed<br>
permissions on all of the resource servers that the authorization server<br>
can give out permissions for. It is possible for a client to have multiple<br>
access tokens with different permissions from the same authorization server<br>
but the client would have to keep track of which permissions were granted<br>
by which token (and the user would have had to confirm that the client<br>
should be granted each set of permissions).<br>
<br>
.. question:: an access token can contain permissions for multiple resource<br>
servers. How do we secure the token from being used maliciously by a<br>
different resource server? ie: I get an access token which grants some<br>
permissions on both fas and bodhi. I send that access token to fas to<br>
retrieve some information. What prevents fas from hanging onto that token<br>
and using it to access the protected resources on bodhi that it grants<br>
without my knowledge?<br>
<br></blockquote><div style>Every request send to auth server or resources server have to be signed </div><div style>with a consumer secret related to the token/access_token which mean that any other program than</div><div style>
the one which get that access token can't get through</div><div style><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
== But wait, there's more! ==<br>
<br>
We've now seen one authorization via oauth. But Oauth is flexible. There's a<br>
few different ways this can work to be aware of:<br>
<br>
* Other ways to request the access token. The example above is what works best<br>
for third-party web clients. However, there's other flows that might work<br>
better for CLI apps or "trusted" web clients<br>
- Implicit: user gets the access token directly from the authorization server<br>
rather than through a authorization code. This sortcut is useful when the<br>
client is entirely in the browser (no third-party server involved). With a<br>
third party server, the authorization code makes it so the user never sees<br>
the actual access token, only the authorization code. if the client is<br>
running on the user's machine anyhow, there's no sense in that step.<br>
- Resource owner password credentials: The resource owner provides their<br>
credentials (username and password) to the client. The client retrieves<br>
the access token from the authorization server using the credentials. Then<br>
it discards the credentials and only keeps the access token for further<br>
requests.<br>
- Client credentials: Just defines that if the client is the resource server,<br>
it can authenticate itself to access its own resources... I'm a little<br>
unclear on this but I think one use would be for a resource server to use<br>
its externally available functions (which are protected by oauth) rather<br>
than having to write an equivalent function that is usable internally.<br>
puiterwijk mentions a different use: having a strict separation between<br>
tenants in the resource server's model and then having to prove you have<br>
permission to access the resource from a different tenant (not something<br>
we're likely to do).<br>
* Verification of the access token can take many forms.<br>
- The authorization server could notify the resource server whenever a new<br>
access token is issued/revoked<br>
- The resource server could ask the authorization server to verify the token<br>
each time it receives one<br>
- The token could be signed by the auth server and thus be verifiable in and<br>
of itself. The token could then contain the list of permissions so that<br>
the resource server would just consult the token to know what was<br>
available. This should not be preferred as it makes revoking a token<br>
harder.<br>
* The authorization server may or may not know about the range of permissions<br>
that it can grant. The resource server needs to interpret what the<br>
permissions the access token grants mean so if the authorization server<br>
grants a made-up permission the application should just ignore it.<br>
<br>
.. question:: Is it possible for the user to grant some of the requested<br>
permissions and deny others? Or is it all or nothing?<br></blockquote><div><br></div><div style>It's all or nothing.</div><div style>It's obvious, if you deny access to requested resources, the related token get revoked.</div>
<div style><br></div><div style>We have a case at work where we have 20 tokens for one resources server.</div><div style>it's just a matter of security level/choice.</div><div style><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
== Refreshing a token and its caveats ==<br>
<br>
An access token can have an expire time. The expire time can be coupled with a<br>
second token called a refresh token. Usually the refresh token would expire<br>
sometime after the access token would expire. When the access token expires,<br>
the refresh token could be used by the client to request a new access token<br>
without prompting the user. This is indended to protect against an attacker<br>
who is sniffing packets from amassing enough ciphertext from multiple uses of a<br>
single access token to be able to brute force that token.<br>
<br>
This sort of automatic expiration and refresh **is not** meant to protect the<br>
user in case the access token is copied without their knowledge (because the<br>
refresh token can be copied at the same time).<br>
<br>
= Part II: How do we use this? =<br>
<br>
This section is less about OAuth itself but some proposals about how we can<br>
best code OAuth usage in our web applications to be secure and featureful.<br>
<br>
== Session vs token ==<br>
<br>
Currently we have a concept of a session in all of our web apps. You login.<br>
Once you're logged in, the web app knows that future connections from your web<br>
browser/CLI/etc are being made by you. At some point the session expires or<br>
you explicitly log out. At that point, the session is over. The expiration<br>
time for most of our apps is currently 20 minuts of idle time but we've talked<br>
about increasing this in the past. Sessions in my mind should last tens of<br>
minutes to hours. Certainly no more than a day. A session conceptually tells<br>
the server that the user is present and interacting with the website (by saying<br>
that the user has "recently" authenticated).<br>
<br>
Tokens are more akin to passwords coupled with a restricted set of permissions.<br>
They're intended to be valid for days to weeks. Refresh tokens can (but don't<br>
necessarily) be used to keep a low amount of ciphertext in the system while<br>
still making authentication via access token transparent to the client.<br>
Conceptually, they tell the server that the **client** (not user) is the same<br>
one that was granted the permissions.<br>
<br>
=== Using tokens to implement sessions ===<br>
<br>
* Sessions need to be short term -- expiration would need to be low (perhaps an<br>
hour). No possibility to refresh the token. If you need to continue, you<br>
have to re-send your username + password (+ otp?)<br>
* We want this specific token to represent that the user is present, not just<br>
that the client has been delegated permissions.<br>
* It would make sense for the token to give out all permissions that the user<br>
has (at least, on this resource server) because the user is present. Example<br>
token permission: "*@*" permissions token<br>
* If possible, saving this type of session token into a wallet/keyring would<br>
make sense as that would encrypt the on-disk representation. However, we'd<br>
also have to account for the fact that these services might not be present.<br>
* Suggested to have access tokens with validity of 5 minutes. refresh tokens<br>
of 20 minutes. This would approximate our current cookie-based idle timeout.<br>
<br>
.. question:: Can we also have a maximum number of refreshes or maximum time<br>
before the user has to reenter their credentials (username + password<br>
(+otp?))<br>
<br>
== Some proposed best practices ==<br>
<br>
* Oauth allows for very granular permissions. You could put a separate<br>
permission on each resource that a client can request. However, it doesn't<br>
require that you are granular or not because the application interprets the<br>
meaning of the permission. A lazy resource server could have a single<br>
permission that covered anything that can be performed on the server but this<br>
means that a stolen token can be used to do anything that that user could do<br>
on that resource server. We should attempt to identify common use cases and<br>
code separate permissions for them. ie: "building a package in a copr" would<br>
belong in a separate permission from "creating a new copr".<br></blockquote><div><br></div><div style>I'm definitively +1 on this one.</div><div style> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
* An access token should not be taken to represent the presence of the user.<br>
It means the user has delegated permission to perform this action to some<br>
"client". It is possible that the client is a command line app or an api and<br>
the user is interacting with it directly but it cannot be assunmed that this<br>
is the case.<br></blockquote><div><br></div><div style>+1 Also, all allowed access should be revoke-able by the user at any time.</div><div style> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
* Following from that, changing authentication methods, password, yubikey,<br>
security questions, etc should never be allowed via an access token. We want<br>
the user to be present to change these settings.<br>
<br></blockquote><div style>+1</div><div style><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
* Tokens and sessions should not contain information about the authentication<br>
status. They should not contain what permissions are held or when the<br>
session expires. These are for the resource server and authorization server<br>
to determine.<br></blockquote><div> </div><div style>Yeah, that's the resource sever which actually defines what third-parties are allowed to</div><div style>to get from it even if token is granted.</div><div style>
<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
* Also following from that -- we should write things to allow for a session to<br>
be sufficient for allowing users to perform actions. access tokens describe<br>
a subset of the functions that the user themselves is allowed to perform.<br>
<br>
* Client side -- we want to have different permissions if the user is running<br>
the cli from the command line vs running the cli from a cron job. A user<br>
running from the cli could be said to have a session.<br>
<br></blockquote><div style>Hmm... I'm not sure we can really prevent user from running the exact same cmd-line from a terminal</div><div style>to a cron tab.</div><div style>Unless having strong policies on user/admin's operation. SOP!</div>
<div style><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
IRC log (since this is all paraphrased and I could have misunderstood what puiterwijk meant):<br>
<br>
<a href="http://toshio.fedorapeople.org/puiterwijk-oauth.html" target="_blank">http://toshio.fedorapeople.org/puiterwijk-oauth.html</a><br>
<span class="HOEnZb"><font color="#888888"><br></font></span></blockquote></div><br clear="all"><div><br></div>-- <br>Xavier <br><br><br></div></div>