Do not set full name when not allowed by Realm

Gerrit API for setting the full name may not be allowed
by the authentication Realm, therefore the execution of
the REST-API to set that information from the SAML
plugin may fail.

It is better to avoid setting the full name rather
than having a failed authentication: the underlying Realm
in Gerrit will have a way to populate the missing information.

Change-Id: I4a5687df90c177551cf405ff09e99ab26c659d86
diff --git a/src/main/java/com/googlesource/gerrit/plugins/saml/SamlWebFilter.java b/src/main/java/com/googlesource/gerrit/plugins/saml/SamlWebFilter.java
index cb6b769..2a73b44 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/saml/SamlWebFilter.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/saml/SamlWebFilter.java
@@ -24,8 +24,10 @@
 import com.google.gerrit.entities.Account;
 import com.google.gerrit.extensions.api.GerritApi;
 import com.google.gerrit.extensions.api.accounts.Accounts;
+import com.google.gerrit.extensions.client.AccountFieldName;
 import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.extensions.restapi.Url;
+import com.google.gerrit.server.account.Realm;
 import com.google.gerrit.server.config.AuthConfig;
 import com.google.gerrit.server.config.CanonicalWebUrl;
 import com.google.gerrit.server.config.SitePaths;
@@ -84,10 +86,12 @@
   private final GerritApi gApi;
   private final Accounts accounts;
   private final OneOffRequestContext oneOffRequestContext;
+  private final boolean realmAllowsFullNameEditing;
 
   @Inject
   SamlWebFilter(
       AuthConfig auth,
+      Realm realm,
       @CanonicalWebUrl @Nullable String canonicalUrl,
       SitePaths sitePaths,
       SamlConfig samlConfig,
@@ -103,6 +107,7 @@
     }
 
     this.samlConfig = samlConfig;
+    this.realmAllowsFullNameEditing = realm.allowsEdit(AccountFieldName.FULL_NAME);
     this.samlMembership = samlMembership;
     log.debug("Max Authentication Lifetime: " + samlConfig.getMaxAuthLifetimeAttr());
     SAML2Configuration samlClientConfig =
@@ -183,17 +188,21 @@
         } else {
           HttpServletRequest req = new AuthenticatedHttpRequest(httpRequest, user);
 
-          HttpServletBufferedStatusResponse respWrapper =
-              new HttpServletBufferedStatusResponse(httpResponse);
-          chain.doFilter(req, respWrapper);
-          try (ManualRequestContext ignored =
-              oneOffRequestContext.openAs(
-                  Account.id(accounts.id(user.getUsername()).get()._accountId))) {
-            gApi.accounts().id(user.getUsername()).setName(user.getDisplayName());
-            respWrapper.commit();
-          } catch (RestApiException e) {
-            log.error("Saml plugin could not set account name", e);
-            httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
+          if (realmAllowsFullNameEditing) {
+            HttpServletBufferedStatusResponse respWrapper =
+                new HttpServletBufferedStatusResponse(httpResponse);
+            chain.doFilter(req, respWrapper);
+            try (ManualRequestContext ignored =
+                oneOffRequestContext.openAs(
+                    Account.id(accounts.id(user.getUsername()).get()._accountId))) {
+              gApi.accounts().id(user.getUsername()).setName(user.getDisplayName());
+              respWrapper.commit();
+            } catch (RestApiException e) {
+              log.error("Saml plugin could not set account name", e);
+              httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
+            }
+          } else {
+            chain.doFilter(req, httpResponse);
           }
         }
       } else if (isGerritLogout(httpRequest)) {
diff --git a/src/test/java/com/googlesource/gerrit/plugins/saml/SamlWebFilterIT.java b/src/test/java/com/googlesource/gerrit/plugins/saml/SamlWebFilterIT.java
index c1e41e5..e12e4a9 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/saml/SamlWebFilterIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/saml/SamlWebFilterIT.java
@@ -18,7 +18,8 @@
 import static com.google.common.truth.Truth.assertThat;
 import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
 import static javax.servlet.http.HttpServletResponse.SC_OK;
-import static org.mockito.Mockito.any;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
@@ -26,15 +27,21 @@
 import com.google.gerrit.acceptance.AbstractDaemonTest;
 import com.google.gerrit.extensions.api.GerritApi;
 import com.google.gerrit.extensions.api.accounts.Accounts;
+import com.google.gerrit.extensions.client.AccountFieldName;
 import com.google.gerrit.extensions.common.AccountDetailInfo;
 import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.server.ServerInitiated;
+import com.google.gerrit.server.account.AccountsUpdate;
+import com.google.gerrit.server.account.Realm;
 import com.google.gerrit.server.config.AuthConfig;
 import com.google.gerrit.server.config.SitePaths;
 import com.google.gerrit.server.util.OneOffRequestContext;
 import com.google.gerrit.testing.ConfigSuite;
 import com.google.gerrit.util.http.testutil.FakeHttpServletRequest;
 import com.google.gerrit.util.http.testutil.FakeHttpServletResponse;
+import com.google.inject.Inject;
 import com.google.inject.Injector;
+import com.google.inject.Provider;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
@@ -48,6 +55,8 @@
 
 public class SamlWebFilterIT extends AbstractDaemonTest {
 
+  @Inject @ServerInitiated private Provider<AccountsUpdate> accountsUpdateProvider;
+
   @ConfigSuite.Default
   public static Config setupSaml() throws ConfigInvalidException {
     Config cfg = new Config();
@@ -92,7 +101,10 @@
   @Test
   public void failAuthenticationWhenAccountManipulationFails()
       throws IOException, ServletException, RestApiException {
-    SamlWebFilter samlWebFilter = newSamlWebFilter(newGerritApiMockFailingOnAccountsApi());
+    SamlWebFilter samlWebFilter =
+        newSamlWebFilter(
+            server.getTestInjector().getInstance(Realm.class),
+            newGerritApiMockFailingOnAccountsApi());
     List<Integer> responseStatuses = new ArrayList<>();
 
     HttpServletResponse res =
@@ -152,10 +164,11 @@
     return apiMock;
   }
 
-  private SamlWebFilter newSamlWebFilter(GerritApi gerritApi) throws IOException {
+  private SamlWebFilter newSamlWebFilter(Realm realm, GerritApi gerritApi) throws IOException {
     Injector testInjector = server.getTestInjector();
     return new SamlWebFilter(
         testInjector.getInstance(AuthConfig.class),
+        realm,
         "",
         testInjector.getInstance(SitePaths.class),
         testInjector.getInstance(SamlConfig.class),
@@ -165,6 +178,30 @@
         testInjector.getInstance(OneOffRequestContext.class));
   }
 
+  @Test
+  public void shouldSucceedAndNotSetFullNameWhenNotAllowedByRealm() throws Exception {
+    Realm realmMock = mock(Realm.class);
+    doReturn(false).when(realmMock).allowsEdit(eq(AccountFieldName.FULL_NAME));
+    SamlWebFilter samlWebFilter = newSamlWebFilter(realmMock, gApi);
+
+    String samlDisplayName = "Test display name";
+
+    HttpSession httpSession = mock(HttpSession.class);
+    AuthenticatedUser authenticatedUser =
+        new AuthenticatedUser(user.username(), samlDisplayName, user.email(), "externalId");
+    doReturn(authenticatedUser).when(httpSession).getAttribute(SamlWebFilter.SESSION_ATTR_USER);
+
+    FakeHttpServletRequest req = new FakeHttpServletRequestWithSession(httpSession);
+    req.setPathInfo(SamlWebFilter.GERRIT_LOGIN);
+    HttpServletResponse res = new FakeHttpServletResponse();
+
+    samlWebFilter.doFilter(req, res, mock(FilterChain.class));
+    assertThat(res.getStatus()).isEqualTo(SC_OK);
+
+    AccountDetailInfo account = gApi.accounts().id(user.username()).detail();
+    assertThat(account.name).isNotEqualTo(samlDisplayName);
+  }
+
   private static class FakeHttpServletRequestWithSession extends FakeHttpServletRequest {
     HttpSession session;