Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch to Auth0 for authentication, stop providing authentication to other services #9

Closed
djmitche opened this issue Mar 31, 2017 · 19 comments

Comments

@djmitche
Copy link
Contributor

djmitche commented Mar 31, 2017

We currently do a poor job of providing authentication to other services, notably treeherder. We do a swell job of providing authorization, though! Let's reposition ourselves so that we provide a really awesome mechanism for API access control that is usable both by API implementers and API users. We are already pretty awesome for API implementers, so this idea only changes the situation for API users.

Proposal

use a three-party authentication system to allow user-facing apps to get taskcluster credentials for their users. The parties are

  • the user
  • the client (a webapp, like treeherder or tools)
  • the resource server (taskcluster)

The flow is this:

  • Client authenticates the user using Auth0, using an OIDC request that includes taskcluster as an audience.
  • Client can use this authentication information directly.
  • Client passes the resulting OIDC token to Taskcluster requesting corresponding TC credentials. TC verifies the token, looks up additional user information, and genereates and returns the credentials.
  • Client accesses TC APIs on behalf of the user with the resulting credentials.

This corresponds to the Auth0 "API" functionality, with TC taking the part of the API. It's a little different from Auth0's plan in that Auth0 expects the API to accept OIDC tokens directly, whereas TC expects TC credentials. So we add the single OIDC -> TC credential transaction for that purpose.

Advantages

With this in place, we can transition services currently using the login.taskcluster.net redirect flow for logins to instead use this mechanism. This includes Treeherder, Treestatus, and probably a few others. The advantage for these users comes from better support for authentication (they get a rich set of information from auth0) and a more dynamic login process. It also puts the burden of user management on the IAM team, and not us.

Links

@djmitche
Copy link
Contributor Author

@garbas is interested in working on this, too.

@djmitche
Copy link
Contributor Author

djmitche commented Apr 3, 2017

I'm exploring the Server + Client API quick-start as it seems to be a good option.

Fooling around was here: taskcluster/taskcluster-login@master...djmitche:auth0api. Open questions:

  • does the user always have to re-auth to get the api access_token?
  • if my app wants to use the auth0 profile and get an api access_token, does the user have to auth twice?
  • how does the API get user info from the api access_token?

@djmitche djmitche self-assigned this Apr 3, 2017
@garbas
Copy link

garbas commented Apr 4, 2017

I would also invite @srfraser since he has more experience with Auth0

@djmitche
Copy link
Contributor Author

djmitche commented Apr 4, 2017

So what I've been working on is the auth0 API authentication model. Concretely, my plan has been this:

It has some rough edges, and I'm not sure it's going to work. The big issue is, the access_token is a JWT that contains very little information about the user, so I don't see how the /v1/credentials endpoint would construct appropriate scopes for the temporary certificate. I asked on the Auth0 Community boards, and the answer so far is to use Rules to insert additional claims into the JWT -- but I don't think I could fit enough information into a JWT..

@srfraser
Copy link

srfraser commented Apr 4, 2017

The Python API makes further calls to the userinfo_uri when needing more data about a user, is that the call that's not working for you?

https://github.com/puiterwijk/flask-oidc/blob/master/flask_oidc/__init__.py#L240

where the userinfo_uri is specified in https://auth.mozilla.auth0.com/.well-known/openid-configuration

@djmitche
Copy link
Contributor Author

djmitche commented Apr 4, 2017

That's equivalent -- I think -- to what I was trying to do here:
taskcluster/taskcluster-login@master...djmitche:auth0api#diff-e6a5b42b2f7a26c840607370aed5301aR199

        let a0 = new auth0js.WebAuth({
          domain: cfg.auth0.domain,
          clientID: 'l23BM36nbr3pUHBkwWqjCrYLiqV3YG3n',
        });
        let accessToken = req.headers.authorization.split(' ')[1];
        a0.client.userInfo(accessToken, (error, user) => {

and I was getting 401 errors, regardless of the clientId I supplied. I suspect that in the flask_oidc code you point to, the fact of bearing the access_token entitles the caller to the user information, since no other secret information is provided in the call. So I further suspect that the access_token I get granting the client access to my API does not have associated user info, hence the 401. But I'm just guessing.

@srfraser
Copy link

srfraser commented Apr 4, 2017

I'm guessing you've already tried the variant mentioned at https://auth0.com/docs/libraries/auth0js/v8#extract-the-authresult-and-get-user-info ?

@djmitche
Copy link
Contributor Author

djmitche commented Apr 5, 2017

I think so? I think that's the equivalent of let accessToken = req.headers.authorization.split(' ')[1]; (the code here is server-side, so there's no window.location.hash to parse). But maybe I should be using the id token instead of the access token? I find auth0's documentation to be at once awesome (there's a lot of it) and maddening (there's a lot of it, and it's not in any linear order, and most of it is not linked from the table of contents)

@djmitche
Copy link
Contributor Author

djmitche commented Apr 5, 2017

Ah, I think the difference is, in that case, the auth0 instance was initialized with the client's credentials (domain and clientID). Hmm. OK, I can mess with this a bit more and see what works.

@djmitche
Copy link
Contributor Author

djmitche commented Apr 6, 2017

The community post didn't turn up much of use - it's possible to inject a little info into the jwt, using Auth0 Rules. And there's a suggestion to use hooks to synchronize LDAP, gihtub, etc. into a local user database -- but there are not hooks defined for changes to that information, so I don't think that would work.

@djmitche
Copy link
Contributor Author

djmitche commented Apr 6, 2017

OK, I had some success after fooling around. The critical bit was to request the openid scope when going to the /authorize endpoint. With that, the access_token can be used with the /userinfo endpoint. it remains to be seen if I can get enough claims to actually generate credentials!

@djmitche
Copy link
Contributor Author

Concept is proven (taskcluster/taskcluster-login#48). This isn't quite ready to implement yet, but I think everyone is agreed that this is the way forward.

@djmitche djmitche removed their assignment Apr 26, 2017
@gdestuynder
Copy link

As a side note, our auth0 prod now supports the API calls as well (just like dev), since last saturday

@djmitche
Copy link
Contributor Author

Happening this quarter!

@djmitche
Copy link
Contributor Author

@gregarndt
Copy link

Getting closer to complete! \o/

@djmitche
Copy link
Contributor Author

I'll be turning off Okta support today, but Auth0's up and running and has been for a few days now.

@djmitche
Copy link
Contributor Author

OK, Okta's off. We're stlil providing auth to other services, but that will end soon enough.

@djmitche
Copy link
Contributor Author

djmitche commented Feb 7, 2018

djmitche added a commit that referenced this issue Feb 7, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants