Просмотр исходного кода

[git-bridge] Add support for Oauth2 Personal Access Tokens (#12795)

* [git-bridge] Add support for Oauth2 Personal Access Tokens

Adds support for Personal Access Tokens by sending a Bearer
token authentication when the username is `git`.
The feature is controlled by `GIT_BRIDGE_ACCESS_TOKEN_ENABLED`

---------

Co-authored-by: Eric Mc Sween <5454374+emcsween@users.noreply.github.com>
GitOrigin-RevId: 5553b0b68574158ede86ceec6c618cf4c4b09c92
Miguel Serrano 3 лет назад
Родитель
Сommit
0564532f92

+ 1 - 0
services/git-bridge/conf/envsubst_template.json

@@ -11,6 +11,7 @@
     "oauth2ClientSecret": "${GIT_BRIDGE_OAUTH2_CLIENT_SECRET}",
     "oauth2Server": "${GIT_BRIDGE_OAUTH2_SERVER:-https://localhost}"
   },
+  "userPasswordEnabled": ${GIT_BRIDGE_USER_PASSWORD_ENABLED:-true},
   "repoStore": {
     "maxFileNum": ${GIT_BRIDGE_REPOSTORE_MAX_FILE_NUM:-2000},
     "maxFileSize": ${GIT_BRIDGE_REPOSTORE_MAX_FILE_SIZE:-52428800}

+ 9 - 0
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/application/config/Config.java

@@ -31,6 +31,7 @@ public class Config implements JSONSource {
                 config.postbackURL,
                 config.serviceName,
                 Oauth2.asSanitised(config.oauth2),
+                config.userPasswordEnabled,
                 config.repoStore,
                 SwapStoreConfig.sanitisedCopy(config.swapStore),
                 config.swapJob,
@@ -47,6 +48,7 @@ public class Config implements JSONSource {
     private String serviceName;
     @Nullable
     private Oauth2 oauth2;
+    private boolean userPasswordEnabled;
     @Nullable
     private RepoStoreConfig repoStore;
     @Nullable
@@ -75,6 +77,7 @@ public class Config implements JSONSource {
             String postbackURL,
             String serviceName,
             Oauth2 oauth2,
+            boolean userPasswordEnabled,
             RepoStoreConfig repoStore,
             SwapStoreConfig swapStore,
             SwapJobConfig swapJob,
@@ -88,6 +91,7 @@ public class Config implements JSONSource {
         this.postbackURL = postbackURL;
         this.serviceName = serviceName;
         this.oauth2 = oauth2;
+        this.userPasswordEnabled = userPasswordEnabled;
         this.repoStore = repoStore;
         this.swapStore = swapStore;
         this.swapJob = swapJob;
@@ -118,6 +122,7 @@ public class Config implements JSONSource {
             postbackURL += "/";
         }
         oauth2 = new Gson().fromJson(configObject.get("oauth2"), Oauth2.class);
+        userPasswordEnabled = getOptionalString(configObject, "userPasswordEnabled").equals("true");
         repoStore = new Gson().fromJson(
                 configObject.get("repoStore"), RepoStoreConfig.class);
         swapStore = new Gson().fromJson(
@@ -173,6 +178,10 @@ public class Config implements JSONSource {
         return oauth2 != null;
     }
 
+    public boolean isUserPasswordEnabled() {
+        return userPasswordEnabled;
+    }
+
     public Oauth2 getOauth2() {
         if (!isUsingOauth2()) {
             throw new AssertionError("Getting oauth2 when not using it");

+ 5 - 1
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/server/GitBridgeServer.java

@@ -166,7 +166,11 @@ public class GitBridgeServer {
         final ServletContextHandler servletContextHandler =
                 new ServletContextHandler(ServletContextHandler.SESSIONS);
         if (config.isUsingOauth2()) {
-            Filter filter = new Oauth2Filter(snapshotApi, config.getOauth2());
+            Filter filter = new Oauth2Filter(
+                    snapshotApi,
+                    config.getOauth2(),
+                    config.isUserPasswordEnabled()
+            );
             servletContextHandler.addFilter(
                     new FilterHolder(filter),
                     "/*",

+ 37 - 27
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/server/Oauth2Filter.java

@@ -32,9 +32,12 @@ public class Oauth2Filter implements Filter {
 
     private final Oauth2 oauth2;
 
-    public Oauth2Filter(SnapshotApi snapshotApi, Oauth2 oauth2) {
+    private final boolean isUserPasswordEnabled;
+
+    public Oauth2Filter(SnapshotApi snapshotApi, Oauth2 oauth2, boolean isUserPasswordEnabled) {
         this.snapshotApi = snapshotApi;
         this.oauth2 = oauth2;
+        this.isUserPasswordEnabled = isUserPasswordEnabled;
     }
 
     @Override
@@ -151,42 +154,49 @@ public class Oauth2Filter implements Filter {
                         if (split.length == 2) {
                             String username = split[0];
                             String password = split[1];
-                            String accessToken = null;
-                            if (username.length() > 0) {
-                                capturedUsername = username;
-                            }
-                            try {
-                                accessToken = new PasswordTokenRequest(
+
+                            final Credential cred = new Credential.Builder(
+                                BearerToken.authorizationHeaderAccessMethod()
+                            ).build();
+
+                            if(username.equals("git")) {
+                                Log.debug("[{}] username is 'git', skipping password grant flow", projectName);
+                                cred.setAccessToken(password);
+                            } else if (this.isUserPasswordEnabled) {
+                                String accessToken = null;
+                                if (username.length() > 0) {
+                                    capturedUsername = username;
+                                }
+                                try {
+                                    accessToken = new PasswordTokenRequest(
                                         Instance.httpTransport,
                                         Instance.jsonFactory,
                                         new GenericUrl(
-                                                oauth2.getOauth2Server()
-                                                        + "/oauth/token?client_ip="
-                                                        + clientIp
+                                    oauth2.getOauth2Server()
+                                            + "/oauth/token?client_ip="
+                                            + clientIp
                                         ),
                                         username,
                                         password
-                                ).setClientAuthentication(
-                                        new ClientParametersAuthentication(
-                                                oauth2.getOauth2ClientID(),
-                                                oauth2.getOauth2ClientSecret()
-                                        )
-                                ).execute().getAccessToken();
-                            } catch (TokenResponseException e) {
-                                handleNeedAuthorization(projectName, capturedUsername, e.getStatusCode(), request, response);
-                                return;
+                                    ).setClientAuthentication(
+                                      new ClientParametersAuthentication(
+                                        oauth2.getOauth2ClientID(),
+                                        oauth2.getOauth2ClientSecret()
+                                      )
+                                    ).execute().getAccessToken();
+                                } catch (TokenResponseException e) {
+                                    handleNeedAuthorization(projectName, capturedUsername, e.getStatusCode(), request, response);
+                                    return;
+                                }
+                                cred.setAccessToken(accessToken);
                             }
-                            final Credential cred = new Credential.Builder(
-                                    BearerToken.authorizationHeaderAccessMethod(
-                                    )
-                            ).build();
-                            cred.setAccessToken(accessToken);
-                            servletRequest.setAttribute(ATTRIBUTE_KEY, cred);
 
+                            servletRequest.setAttribute(ATTRIBUTE_KEY, cred);
                             filterChain.doFilter(
-                                    servletRequest,
-                                    servletResponse
+                                servletRequest,
+                                servletResponse
                             );
+
                         } else {
                             handleNeedAuthorization(projectName, capturedUsername, 0, request, response);
                         }

+ 2 - 1
services/git-bridge/src/test/java/uk/ac/ic/wlgitbridge/application/config/ConfigTest.java

@@ -92,6 +92,7 @@ public class ConfigTest {
                 "    \"oauth2ClientSecret\": \"<oauth2ClientSecret>\",\n" +
                 "    \"oauth2Server\": \"https://www.overleaf.com\"\n" +
                 "  },\n" +
+                "  \"userPasswordEnabled\": false,\n" +
                 "  \"repoStore\": null,\n" +
                 "  \"swapStore\": null,\n" +
                 "  \"swapJob\": null,\n" +
@@ -104,4 +105,4 @@ public class ConfigTest {
         );
     }
 
-}
+}

+ 1 - 0
services/git-bridge/src/test/java/uk/ac/ic/wlgitbridge/bridge/BridgeTest.java

@@ -62,6 +62,7 @@ public class BridgeTest {
                         "",
                         "",
                         null,
+                        false,
                         null,
                         null,
                         null,