Last active
April 15, 2024 09:45
-
-
Save proton5000/672b5e9e81193ff38509384f2e4f7fa2 to your computer and use it in GitHub Desktop.
Revisions
-
proton5000 revised this gist
Apr 15, 2024 . 1 changed file with 38 additions and 25 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -4,6 +4,7 @@ import com.nimbusds.jose.jwk.JWK; import com.nimbusds.jose.jwk.JWKSet; import io.jsonwebtoken.Claims; import io.jsonwebtoken.JwsHeader; import io.jsonwebtoken.Jwts; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; @@ -29,7 +30,7 @@ public class AppCheckFilter extends OncePerRequestFilter { private static final String FIREBASE_APP_CHECK_URL = "https://firebaseappcheck.googleapis.com/v1/jwks"; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String token = request.getHeader("HTTP_X_FIREBASE_APPCHECK"); @@ -50,66 +51,78 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse } private String checkToken(String token) { // Load JWKS keys from a file or URL try { // Not necessary to get the public keys each time, it can be cached for 6 hours, // info from docs https://firebase.google.com/docs/app-check/custom-resource-backend#other String jwksString = IOUtils.toString(new URL(FIREBASE_APP_CHECK_URL), Charset.defaultCharset()); JWKSet jwks = JWKSet.parse(jwksString); // Extract JWK with given kid for (JWK jwk : jwks.toPublicJWKSet().getKeys()) {// Use JWK to verify JWT signature try { // If a getting claims not throw the exception it's like You can already trust your mobile application, // it has a signature, but to clarify that it is your application, you can check the following statements Claims claims = Jwts.parser() .verifyWith(jwk.toRSAKey().toRSAPublicKey()) .build() .parseSignedClaims(token) .getPayload(); JwsHeader header = Jwts.parser() .verifyWith(jwk.toRSAKey().toRSAPublicKey()) .build() .parseSignedClaims(token) .getHeader(); for (String claimName : claims.keySet()) { System.out.println(claimName + ": " + claims.get(claimName)); } // Validate claims, you can choose what is better to validate for your app if (!header.getAlgorithm().equals("RS256")) { return null; } if (!header.getType().equals("JWT")) { return null; } if (!claims.getIssuer().equals("https://firebaseappcheck.googleapis.com/#" + PROJECT_NUMBER)) { return null; } if (claims.getExpiration().before(new Date())) { return null; } if (!claims.getAudience().contains("projects/" + PROJECT_NUMBER)) { return null; } System.out.println("header -> " + header.getAlgorithm()); System.out.println("type -> " + header.getType()); System.out.println("issuer -> " + claims.getIssuer()); System.out.println("audience -> " + claims.getAudience().contains("projects/" + PROJECT_NUMBER)); System.out.println("expiration -> " + claims.getExpiration().before(new Date())); System.out.println("subject -> " + claims.getSubject()); System.out.println("Signature is valid"); return claims.getSubject(); } catch (JOSEException e) { System.out.println("mess_1 -> " + e.getMessage()); System.out.println("Failed to verify signature: " + e.getMessage()); } } } catch (IOException | ParseException e) { System.out.println("mess_2 -> " + e.getMessage()); } -
proton5000 revised this gist
Apr 15, 2024 . No changes.There are no files selected for viewing
-
proton5000 revised this gist
Apr 15, 2024 . 1 changed file with 3 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,5 +1,6 @@ package ua.varus.scan.and.go.config.security; import com.nimbusds.jose.JOSEException; import com.nimbusds.jose.jwk.JWK; import com.nimbusds.jose.jwk.JWKSet; import io.jsonwebtoken.Claims; @@ -28,7 +29,7 @@ public class AppCheckFilter extends OncePerRequestFilter { private static final String FIREBASE_APP_CHECK_URL = "https://firebaseappcheck.googleapis.com/v1/jwks"; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String token = request.getHeader("HTTP_X_FIREBASE_APPCHECK"); @@ -100,7 +101,7 @@ private String checkToken(String token) { System.out.println("Signature is valid"); return claims.getSubject(); } catch (JOSEException e) { // e.printStackTrace(); System.out.println("mess_1 -> " + e.getMessage()); System.out.println("Failed to verify signature: " + e.getMessage()); -
proton5000 created this gist
Apr 15, 2024 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,117 @@ package ua.varus.scan.and.go.config.security; import com.nimbusds.jose.jwk.JWK; import com.nimbusds.jose.jwk.JWKSet; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import org.apache.commons.io.IOUtils; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; import java.io.IOException; import java.net.URL; import java.nio.charset.Charset; import java.text.ParseException; import java.util.Date; @Component @RequiredArgsConstructor public class AppCheckFilter extends OncePerRequestFilter { private static final String PROJECT_NUMBER = "1050204332425"; private static final String FIREBASE_APP_CHECK_URL = "https://firebaseappcheck.googleapis.com/v1/jwks"; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String token = request.getHeader("HTTP_X_FIREBASE_APPCHECK"); if (token == null) { response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthenticated"); return; } String appId = checkToken(token); if (appId == null) { response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthenticated"); return; } request.setAttribute("firebase.app", appId); filterChain.doFilter(request, response); } private String checkToken(String token) { // Load JWKS keys from a file or URL try { String jwksString = IOUtils.toString(new URL(FIREBASE_APP_CHECK_URL), Charset.defaultCharset()); JWKSet jwks = JWKSet.parse(jwksString); // Extract JWK with given kid for (JWK jwk : jwks.toPublicJWKSet().getKeys()) {// Use JWK to verify JWT signature try { Claims claims = Jwts.parser() .verifyWith(jwk.toRSAKey().toRSAPublicKey()) .build() .parseSignedClaims(token) .getPayload(); for (String claimName : claims.keySet()) { System.out.println(claimName + ": " + claims.get(claimName)); } // Validate claims // if (!decodedJwt.getAlgorithm().equals("RS256")) { // return null; // } // // if (!decodedJwt.getType().equals("JWT")) { // return null; // } // // if (!decodedJwt.getIssuer().equals("https://firebaseappcheck.googleapis.com/#" + projectNumber)) { // return null; // } // // if (decodedJwt.getExpiresAt().before(new Date())) { // return null; // } // // List<String> audiences = decodedJwt.getAudience(); // if (!audiences.contains("projects/" + projectNumber)) { // return null; // } System.out.println("issuer -> " + claims.getIssuer()); System.out.println("audience -> " + claims.getAudience().contains("projects/" + PROJECT_NUMBER)); System.out.println("expiration -> " + claims.getExpiration().before(new Date())); System.out.println("type -> " + claims.get("type")); System.out.println("subject -> " + claims.getSubject()); System.out.println("Signature is valid"); return claims.getSubject(); } catch (Exception e) { // e.printStackTrace(); System.out.println("mess_1 -> " + e.getMessage()); System.out.println("Failed to verify signature: " + e.getMessage()); } } } catch (IOException | ParseException e) { // e.printStackTrace(); System.out.println("mess_2 -> " + e.getMessage()); } return null; } } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,28 @@ <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.12.5</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>0.12.5</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-gson</artifactId> <version>0.12.5</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <version>0.12.5</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-orgjson</artifactId> <version>0.12.5</version> <scope>runtime</scope> </dependency>