I've written a proof-of-concept script which fetches a file from a
protected svn repo, and posted it on the dev list
<https://lists.apache.org/thread/f3f516vkm16ss67g9xfrjrfdcp70ymd0>. With
a bit of luck, this might get someone interested in adding the OAuth2
code to svn and TSVN.
-Evan
On 30/03/2024 13:40, EML wrote:
Hi Thomas/Daniel/etc. First, standard disclaimer: this isn't my day
job, and I'm still new to OIDC, so apologies if any of this is
wrong/too obvious/whatever. On your points:
(1) HTTP requests need to specify 'Authorization: Bearer' with an access
token.
Are you sure mod_openidc accepts a Bearer token when configured with AuthType
openid-connect?
openid-connect is the only OIDC AuthType (the AuthTypes aren't
properly documented, which doesn't help).
I think there may be some confusion here, though (TL;DR: bearer tokens
must be used, and not cookies).
Why? If I just use a browser to connect to an OAuth2-protected
resource which is on a server behind Apache/mod_auth_openidc ('MAO'),
/then I never need, or even see, a bearer token/. The reason is that
this is handled internally by MAO. When I first browse to a protected
resource, MAO sees that I don't have a session cookie, and connects to
the identity provider (which it normally finds from
'OIDCProviderMetadataURL'). MAO then pops ups a login window at the
provider (the 'IdP', ie. Google/github/whatever); the provider then
authenticates and redirects back to MAO. If this works out, MAO sends
back my requested page, /plus a session cookie/. My browser then uses
this session cookie to communicate with the server; it doesn't need
the bearer token.
/But/: this isn't how command-line access would work. Something (GCM,
for the sake of argument) connects /directly/ to the identity provider
(see the 'credential' section in my first post, which tells GCM how to
do this). GCM needs to talk to a 'client' at the IdP (more on this
below). It pops up a login window, goes through a token swap
procedure, and gets a JWT token if successful. GCM now has a token
that it can use to communicate with MAO on my server. This next bit
I'm a bit hazy on, because I've only done minimal testing with GCM.
However, I presume that MAO then uses the JWT from the browser to
communicate back to the IdP to check the token validity (or maybe it
just uses the IdP's known public key to decode the JWT, and then
assumes that it's valid), and then sends me back a session cookie,
just like it does for normal web access.
Note, of course, that we cannot assume that the server with the
protected repo will be running MAO. Frameworks (Tomcat/etc) generally
have their own way to do this (but it's probably safe to assume that
most people who have an svn repo will use MAO). All we know for sure
is that the repo is OAuth2-protected (OIDC, to be precise), and we
have to use the OAuth2 specs. RFC6750
<https://datatracker.ietf.org/doc/html/rfc6750> says in the abstract
that "/This specification describes how to use bearer tokens in HTTP
requests to access OAuth 2.0 protected resources. Any party in
possession of a bearer token (a "bearer") can use it to get access to
the associated resources (without demonstrating possession of a
cryptographic key)./" So, bearer tokens must be used. You can put the
token in a cookie, but you then have to create an agreed name for that
cookie, and I can't imagine that anyone does that. I think the cookie
confusion is to do with session cookies.
However, I think this all pretty moot in out case, unless
you/we/someone intends to re-invent the wheel and write a version of
GCM/git-credential-oauth/oidc-agent/whatever. I've got some time today
and I'm going to try to install oidc-agent and connect through to a
protected svn repo. If I can come up with a 'manual' procedure then
this could be coded up in svn.
This is not the approach we have taken (*due to complexity and uncertainty related to protecting the app
registration client-secret*). We let mod_openidc handle as much complexity as possible.
The client secret is interesting. There are 2 client types
<https://datatracker.ietf.org/doc/html/rfc6749#section-2.1> defined in
the RFC: confidential, and public. They differ in how secure the
client credentials are (not the credentials of the user trying to log
in; the credentials the client app needs to talk to the OAuth server).
You would think that we're taking about a public client here: lots of
people on different computers are trying to access the repo, all using
the same app credentials. But, in fact, everyone's agreed that this
sort of CLI client, carrying out machine to machine (M2M)
communication, is a confidential client. This means that your app (the
thing we're talking about writing here, ie. 'oidc-svn'/whatever) must
use a client secret to talk to the OAuth server. The server uses this
to determine whether the app is authorised to talk to the API. This
means that you have to suck it up and protect the client secret. See
this SO answer <https://stackoverflow.com/a/57762140/785194> for tips
(note that the 'HansZ' referred to is the author of MAO).
If you see my original .gitconfig in this thread you'll see that the
client secret is completely /un/protected - it is (or would be) in
cleartext in an easily accessible file. This is just a simple
hard-wired .gitconfig; I think (I'm not a git expert) I could set up
the credential store and use 'git config' to store the secret in a
more secure way. In any event, the issue here is that svn needs to
store the secret in a better way than in my example. If the secret is
compromised, it can be used to sign JWTs, and get access to the API.
However, this may not be as bad as it sounds: the client can be
created at the OAuth2 server to give it limited permissions (it only
needs to authorise svn users, so doesn't need admin functions). The
redirect URI also gives good security.
-Evan