diff --git a/CHANGELOG.md b/CHANGELOG.md index 05ff4a8a18..d455122b12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Source code fullscreen view ([#1376](https://github.com/scm-manager/scm-manager/pull/1376)) ### Changed +- Reduce logging of ApiTokenRealm ([#1385](https://github.com/scm-manager/scm-manager/pull/1385)) - Centralise syntax highlighting ([#1382](https://github.com/scm-manager/scm-manager/pull/1382)) ## [2.6.3] - 2020-10-16 diff --git a/scm-webapp/src/main/java/sonia/scm/security/ApiKeyRealm.java b/scm-webapp/src/main/java/sonia/scm/security/ApiKeyRealm.java index 672f972dab..a447388d97 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/ApiKeyRealm.java +++ b/scm-webapp/src/main/java/sonia/scm/security/ApiKeyRealm.java @@ -24,6 +24,7 @@ package sonia.scm.security; +import com.google.common.io.BaseEncoding; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.UsernamePasswordToken; @@ -61,13 +62,14 @@ public class ApiKeyRealm extends AuthenticatingRealm { } @Override + @SuppressWarnings("java:S4738") // java.util.Base64 has no canDecode method public boolean supports(AuthenticationToken token) { if (token instanceof UsernamePasswordToken || token instanceof BearerToken) { - boolean containsDot = getPassword(token).contains("."); - if (containsDot) { - LOG.debug("Ignoring token with at least one dot ('.'); this is probably a JWT token"); + boolean isBase64 = BaseEncoding.base64().canDecode(getPassword(token)); + if (!isBase64) { + LOG.debug("Ignoring non base 64 token; this is probably a JWT token or a normal password"); } - return !containsDot; + return isBase64; } return false; } diff --git a/scm-webapp/src/main/java/sonia/scm/security/ApiKeyTokenHandler.java b/scm-webapp/src/main/java/sonia/scm/security/ApiKeyTokenHandler.java index 34ee392060..71478e7bc5 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/ApiKeyTokenHandler.java +++ b/scm-webapp/src/main/java/sonia/scm/security/ApiKeyTokenHandler.java @@ -28,7 +28,6 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import io.jsonwebtoken.io.Decoder; import io.jsonwebtoken.io.Decoders; -import io.jsonwebtoken.io.DecodingException; import io.jsonwebtoken.io.Encoder; import io.jsonwebtoken.io.Encoders; import lombok.AllArgsConstructor; @@ -62,8 +61,8 @@ class ApiKeyTokenHandler { Optional readToken(String token) { try { return of(OBJECT_MAPPER.readValue(decoder.decode(token), Token.class)); - } catch (IOException | DecodingException e) { - LOG.warn("error reading api token", e); + } catch (IOException e) { + LOG.debug("failed to read api token, perhaps it is a jwt token or a normal password", e); return empty(); } } diff --git a/scm-webapp/src/test/java/sonia/scm/security/ApiKeyRealmTest.java b/scm-webapp/src/test/java/sonia/scm/security/ApiKeyRealmTest.java index 0f4171b8d9..f53e845bf2 100644 --- a/scm-webapp/src/test/java/sonia/scm/security/ApiKeyRealmTest.java +++ b/scm-webapp/src/test/java/sonia/scm/security/ApiKeyRealmTest.java @@ -25,6 +25,7 @@ package sonia.scm.security; import org.apache.shiro.authc.AuthenticationToken; +import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authz.AuthorizationException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -105,6 +106,15 @@ class ApiKeyRealmTest { assertThat(supports).isFalse(); } + @Test + void shouldIgnoreNonBase64Tokens() { + UsernamePasswordToken token = new UsernamePasswordToken("trillian", "My&SecretPassword"); + + boolean supports = realm.supports(token); + + assertThat(supports).isFalse(); + } + void verifyScopeSet(String... permissions) { verify(authenticationInfoBuilder).withScope(argThat(scope -> { assertThat(scope).containsExactly(permissions);