CVE-2021-29451 (published 2021-04-16T22:15Z)

Portofino is an open source web development framework. Portofino before version 5.2.1 did not properly verify the signature of JSON Web Tokens. This allows forging a valid JWT. The issue will be patched in the upcoming 5.2.1 release.

Severity: MEDIUM
CVSS v2 base score: 6.4 (AV:N/AC:L/Au:N/C:P/I:P/A:N)
CVSS v3 base score: 9.1, CRITICAL (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N)

Weakness information:
cwe_id: CWE-347
cwe_name: Improper Verification of Cryptographic Signature
description: The product does not verify, or incorrectly verifies, the cryptographic signature for data.
extended_description: 
            
            
         
         

Fix information:
repo_url: https://github.com/ManyDesigns/Portofino
commit_details: repo_url: https://github.com/ManyDesigns/Portofino
author: Alessio Stalla
author_date: 2021-04-01 18:16:16+02:00
msg: Fix security vulnerability
repository: repo_url: https://github.com/ManyDesigns/Portofino
repo_name: ManyDesigns/Portofino
description: Portofino 5 is the next generation of the open-source low-code web framework Portofino. Its purpose is to help developers create modern, responsive enterprise applications with REST APIs and an Angular UI.
repo_language: Java
owner: ManyDesigns
file_changes: filename: CHANGELOG.md
change_type: ModificationType.MODIFY
diff: @@ -13,8 +13,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 - Security.groovy can now have user beans injected with @Autowired.
 
 ### Fixed
-- Backwards compatibility: revert `T extends Serializable` in CRUD actions, introduced in v5.2.0. [#428](https://github.com/ManyDesigns/Portofino/issues/428)
+- Important security vulnerability that may have allowed access with forged tokens.
 - Authentication token refresh after expiration. [#430](https://github.com/ManyDesigns/Portofino/issues/430)
+- Backwards compatibility: revert `T extends Serializable` in CRUD actions, introduced in v5.2.0. [#428](https://github.com/ManyDesigns/Portofino/issues/428)
 
 ## [5.2.0] – 2020-11-30
 

programming_language: Markdown
filename: JWTRealm.java
change_type: ModificationType.MODIFY
diff: @@ -1,9 +1,7 @@
 package com.manydesigns.portofino.dispatcher.security.jwt;
 
 import com.manydesigns.portofino.dispatcher.security.RolesPermission;
-import io.jsonwebtoken.Jwt;
-import io.jsonwebtoken.Jwts;
-import io.jsonwebtoken.SignatureAlgorithm;
+import io.jsonwebtoken.*;
 import io.jsonwebtoken.io.Decoders;
 import org.apache.commons.configuration2.Configuration;
 import org.apache.shiro.authc.AuthenticationException;
@@ -53,9 +51,9 @@ public class JWTRealm extends AuthorizingRealm {
         String secret = getSecret();
         Key key = new SecretKeySpec(Decoders.BASE64.decode(secret), getSignatureAlgorithm().getJcaName());
         
-        Jwt jwt = Jwts.parser().
+        Jws<Claims> jwt = Jwts.parser().
                 setSigningKey(key).
-                parse((String) token.getPrincipal());
+                parseClaimsJws((String) token.getPrincipal());
         Map<String, Serializable> principal = getPrincipal(jwt);
         return new SimpleAuthenticationInfo(principal, ((String) token.getCredentials()).toCharArray(), getName());
     }
@@ -64,7 +62,7 @@ public class JWTRealm extends AuthorizingRealm {
         return SignatureAlgorithm.HS512;
     }
 
-    protected Map<String, Serializable> getPrincipal(Jwt jwt) {
+    protected Map<String, Serializable> getPrincipal(Jws<Claims> jwt) {
         Map<String, Serializable> principal = new HashMap<>();
         principal.put("jwt", (Serializable) jwt.getBody());
         return principal;

programming_language: Java
filename: AbstractPortofinoRealm.java
change_type: ModificationType.MODIFY
diff: @@ -24,10 +24,7 @@ import com.manydesigns.elements.reflection.ClassAccessor;
 import com.manydesigns.elements.reflection.JavaClassAccessor;
 import com.manydesigns.portofino.code.CodeBase;
 import com.manydesigns.portofino.security.SecurityLogic;
-import io.jsonwebtoken.Jwt;
-import io.jsonwebtoken.JwtException;
-import io.jsonwebtoken.Jwts;
-import io.jsonwebtoken.SignatureAlgorithm;
+import io.jsonwebtoken.*;
 import io.jsonwebtoken.io.Decoders;
 import org.apache.commons.configuration2.Configuration;
 import org.apache.shiro.authc.AuthenticationException;
@@ -100,9 +97,9 @@ public abstract class AbstractPortofinoRealm extends AuthorizingRealm implements
 
     public AuthenticationInfo loadAuthenticationInfo(JSONWebToken token) {
         Key key = getJWTKey();
-        Jwt jwt;
+        Jws<Claims> jwt;
         try {
-            jwt = Jwts.parser().setSigningKey(key).parse(token.getPrincipal());
+            jwt = Jwts.parser().setSigningKey(key).parseClaimsJws(token.getPrincipal());
         } catch (JwtException e) {
             throw new AuthenticationException(e);
         }
@@ -111,8 +108,8 @@ public abstract class AbstractPortofinoRealm extends AuthorizingRealm implements
         return new SimpleAuthenticationInfo(principal, credentials, getName());
     }
 
-    protected Object extractPrincipalFromWebToken(Jwt jwt) {
-        Map body = (Map) jwt.getBody();
+    protected Object extractPrincipalFromWebToken(Jws<Claims> jwt) {
+        Map<String, Object> body = jwt.getBody();
         String base64Principal = (String) body.get("serialized-principal");
         byte[] serializedPrincipal = Base64.decode(base64Principal);
         Object principal;

programming_language: Java