16669: Accept OIDC access token in federated requests.
authorTom Clegg <tom@curii.com>
Thu, 4 Mar 2021 21:51:12 +0000 (16:51 -0500)
committerTom Clegg <tom@curii.com>
Thu, 4 Mar 2021 21:51:12 +0000 (16:51 -0500)
...provided both local and remote clusters use the same login cluster.

Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom@curii.com>

lib/controller/federation.go
lib/controller/federation/conn.go
lib/controller/integration_test.go
lib/controller/localdb/login_oidc.go

index cab5e4c4ca45172edb28f07210b001456f1e11af..419d8b01049b21d97ccebe6c5f9ec394208e1336 100644 (file)
@@ -263,10 +263,10 @@ func (h *Handler) saltAuthToken(req *http.Request, remote string) (updatedReq *h
                return updatedReq, nil
        }
 
-       ctxlog.FromContext(req.Context()).Infof("saltAuthToken: cluster %s token %s remote %s", h.Cluster.ClusterID, creds.Tokens[0], remote)
+       ctxlog.FromContext(req.Context()).Debugf("saltAuthToken: cluster %s token %s remote %s", h.Cluster.ClusterID, creds.Tokens[0], remote)
        token, err := auth.SaltToken(creds.Tokens[0], remote)
 
-       if err == auth.ErrObsoleteToken {
+       if err == auth.ErrObsoleteToken || err == auth.ErrTokenFormat {
                // If the token exists in our own database for our own
                // user, salt it for the remote. Otherwise, assume it
                // was issued by the remote, and pass it through
index b86266d67e6f02c170deb631d32c777ecb072781..0f063d1238aac1f045a34c00971a66f0e93a53ce 100644 (file)
@@ -69,6 +69,9 @@ func saltedTokenProvider(local backend, remoteID string) rpc.TokenProvider {
                                tokens = append(tokens, salted)
                        case auth.ErrSalted:
                                tokens = append(tokens, token)
+                       case auth.ErrTokenFormat:
+                               // pass through unmodified (assume it's an OIDC access token)
+                               tokens = append(tokens, token)
                        case auth.ErrObsoleteToken:
                                ctx := auth.NewContext(ctx, &auth.Credentials{Tokens: []string{token}})
                                aca, err := local.APIClientAuthorizationCurrent(ctx, arvados.GetOptions{})
index 3d0639f6ccee1c79e4d4702ff93fbb25a52b9795..db1f7f0d0cee51b359c6d10f9ddd1e1b5de790e3 100644 (file)
@@ -683,15 +683,16 @@ func (s *IntegrationSuite) TestOIDCAccessTokenAuth(c *check.C) {
        accesstoken := s.oidcprovider.ValidAccessToken()
 
        for _, clusterID := range []string{"z1111", "z2222"} {
-               c.Logf("trying clusterid %s", clusterID)
-
-               conn := s.testClusters[clusterID].Conn()
-               ctx, ac, kc := s.testClusters[clusterID].ClientsWithToken(accesstoken)
 
                var coll arvados.Collection
 
                // Write some file data and create a collection
                {
+                       c.Logf("save collection to %s", clusterID)
+
+                       conn := s.testClusters[clusterID].Conn()
+                       ctx, ac, kc := s.testClusters[clusterID].ClientsWithToken(accesstoken)
+
                        fs, err := coll.FileSystem(ac, kc)
                        c.Assert(err, check.IsNil)
                        f, err := fs.OpenFile("test.txt", os.O_CREATE|os.O_RDWR, 0777)
@@ -708,15 +709,22 @@ func (s *IntegrationSuite) TestOIDCAccessTokenAuth(c *check.C) {
                        c.Assert(err, check.IsNil)
                }
 
-               // Read the collection & file data
-               {
+               // Read the collection & file data -- both from the
+               // cluster where it was created, and from the other
+               // cluster.
+               for _, readClusterID := range []string{"z1111", "z2222", "z3333"} {
+                       c.Logf("retrieve %s from %s", coll.UUID, readClusterID)
+
+                       conn := s.testClusters[readClusterID].Conn()
+                       ctx, ac, kc := s.testClusters[readClusterID].ClientsWithToken(accesstoken)
+
                        user, err := conn.UserGetCurrent(ctx, arvados.GetOptions{})
                        c.Assert(err, check.IsNil)
                        c.Check(user.FullName, check.Equals, "Example User")
-                       coll, err = conn.CollectionGet(ctx, arvados.GetOptions{UUID: coll.UUID})
+                       readcoll, err := conn.CollectionGet(ctx, arvados.GetOptions{UUID: coll.UUID})
                        c.Assert(err, check.IsNil)
-                       c.Check(coll.ManifestText, check.Not(check.Equals), "")
-                       fs, err := coll.FileSystem(ac, kc)
+                       c.Check(readcoll.ManifestText, check.Not(check.Equals), "")
+                       fs, err := readcoll.FileSystem(ac, kc)
                        c.Assert(err, check.IsNil)
                        f, err := fs.Open("test.txt")
                        c.Assert(err, check.IsNil)
index 74b8929a2149b14910a88823cb97a5b398a294f9..73b557723752556d4c6071e2d186f4a2a495e65d 100644 (file)
@@ -129,6 +129,7 @@ func (ctrl *oidcLoginController) Login(ctx context.Context, opts arvados.LoginOp
        if err != nil {
                return loginError(fmt.Errorf("error in OAuth2 exchange: %s", err))
        }
+       ctxlog.FromContext(ctx).WithField("oauth2Token", oauth2Token).Debug("oauth2 exchange succeeded")
        rawIDToken, ok := oauth2Token.Extra("id_token").(string)
        if !ok {
                return loginError(errors.New("error in OAuth2 exchange: no ID token in OAuth2 token"))