Skip to content

Commit

Permalink
Detect and tolerate less strict JWS objects than Nimbus. Fixes blackb…
Browse files Browse the repository at this point in the history
  • Loading branch information
DolphFlynn committed Jan 5, 2023
1 parent 9cdea12 commit a196e5a
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,20 @@

package com.blackberry.jwteditor.model.jose;

import com.nimbusds.jose.JOSEObject;
import com.nimbusds.jose.JWEObject;
import com.nimbusds.jose.JWSObject;
import com.nimbusds.jose.util.Base64URL;
import com.nimbusds.jose.util.JSONObjectUtils;

import java.text.ParseException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.nimbusds.jose.Header.MAX_HEADER_STRING_LENGTH;
import static com.nimbusds.jose.HeaderParameterNames.ALGORITHM;
import static org.apache.commons.lang3.StringUtils.isBlank;

public class JOSEObjectFinder {
public static final String BASE64_REGEX = "[A-Za-z0-9-_]";

Expand Down Expand Up @@ -55,7 +61,7 @@ public static List<MutableJOSEObject> extractJOSEObjects(String text) {

return joseObjects;
}

public static boolean containsJOSEObjects(String text) {
Set<String> candidates = findCandidateJoseObjectsWithin(text);

Expand Down Expand Up @@ -95,7 +101,28 @@ private static Optional<JWE> parseJWE(String candidate) {

private static Optional<JWS> parseJWS(String candidate) {
try {
JWSObject.parse(candidate);
Base64URL[] parts = JOSEObject.split(candidate);

if (parts.length != 3) {
throw new ParseException("Unexpected number of Base64URL parts, must be three", 0);
}

// Header must be Base64URL encoded UTF-8 encoded JSON object with 'alg' value
Base64URL encodedHeader = parts[0];
String header = encodedHeader.decodeToString(); // assumes UTF-8
Map<String, Object> headerJson = JSONObjectUtils.parse(header, MAX_HEADER_STRING_LENGTH);

String algValue = JSONObjectUtils.getString(headerJson, ALGORITHM);

if (isBlank(algValue)) {
throw new ParseException("Missing \"alg\" in header JSON object", 0);
}

// Payload must be Base64URL encoded UTF-8 encoded JSON object
Base64URL encodedPayload = parts[1];
String payload = encodedPayload.decodeToString();
JSONObjectUtils.parse(payload); // throws ParseException if not JSON object

return Optional.of(JWS.parse(candidate));
} catch (ParseException e) {
return Optional.empty();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,30 +31,60 @@
import static com.blackberry.jwteditor.model.jose.JOSEObjectFinder.extractJOSEObjects;
import static org.assertj.core.api.Assertions.assertThat;

class JOSEParserTests {
class JOSEObjectFinderTests {
private static Stream<String> validJws() {
return Stream.of(
// JWS
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJUZXN0In0.Nabf3xakZubPnCzHT-fx0vG1iuNPeJKuSzHxUiQKf-8",
// JWS with whitespace
" eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJUZXN0In0.Nabf3xakZubPnCzHT-fx0vG1iuNPeJKuSzHxUiQKf-8 ",
// JWS without signature
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJUZXN0In0.",
// JWS with preceding text
"asdasdasdeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJUZXN0In0.Nabf3xakZubPnCzHT-fx0vG1iuNPeJKuSzHxUiQKf-8",
// JWS without signature preceding text
"asdasdasdasdeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJUZXN0In0.Nabf3xakZubPnCzHT-fx0vG1iuNPeJKuSzHxUiQKf-8"
"asdasdasdasdeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJUZXN0In0.Nabf3xakZubPnCzHT-fx0vG1iuNPeJKuSzHxUiQKf-8",
// JWS with empty payload
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.17DlZn0zeYhz3uTQCRpSx9hYlUj1SJxDMeZLof8dSHw",
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyB9.17DlZn0zeYhz3uTQCRpSx9hYlUj1SJxDMeZLof8dSHw",
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgfQ.17DlZn0zeYhz3uTQCRpSx9hYlUj1SJxDMeZLof8dSH"
);
}

private static Stream<String> invalidJws() {
return Stream.of(
"",
".",
"...",
"asdadasdasdeyJhbGci$iJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJUZXN0In0.Nabf3xakZubPnCzHT-fx0vG1iuNPeJKuSzHxUiQKf-8",
"asdadasdasdeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ^ZXN0In0.Nabf3xakZubPnCzHT-fx0vG1iuNPeJKuSzHxUiQKf-8",
// No header
".eyJzdWIiOiJUZXN0In0.Nabf3xakZubPnCzHT-fx0vG1iuNPeJKuSzHxUiQKf-8",
// No payload
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..Nabf3xakZubPnCzHT-fx0vG1iuNPeJKuSzHxUiQKf-8",
// Empty
"..",
//URL
"www.blackberry.com"
"www.blackberry.com",
// Invalid charset encoding
"K0FIc0FJZy10eXArQUNJOitBQ0ktSldUK0FDSSwrQUNJLWFsZytBQ0k6K0FDSS1IUzI1NitBQ0lBZlEt.eyJzdWIiOiJUZXN0In0.17DlZn0zeYhz3uTQCRpSx9hYlUj1SJxDMeZLof8dSHw",
"_v8AewAiAHQAeQBwACIAOgAiAEoAVwBUACIALAAiAGEAbABnACIAOgAiAEgAUwAyADUANgAiAH0.eyJzdWIiOiJUZXN0In0.17DlZn0zeYhz3uTQCRpSx9hYlUj1SJxDMeZLof8dSHw",
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.K0FIc0FJZy1zdWIrQUNJOitBQ0ktVGVzdCtBQ0lBZlEt.17DlZn0zeYhz3uTQCRpSx9hYlUj1SJxDMeZLof8dSHw",
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9._v8AewAiAHMAdQBiACIAOgAiAFQAZQBzAHQAIgB9.17DlZn0zeYhz3uTQCRpSx9hYlUj1SJxDMeZLof8dSHw",
// Missing or invalid 'alg'
"eyJ0eXAiOiJKV1QifQ.eyJzdWIiOiJUZXN0In0.17DlZn0zeYhz3uTQCRpSx9hYlUj1SJxDMeZLof8dSHw",
"eyJ0eXAiOiJKV1QiLCJhbGciOiIifQ.eyJzdWIiOiJUZXN0In0.17DlZn0zeYhz3uTQCRpSx9hYlUj1SJxDMeZLof8dSHw",
"eyJ0eXAiOiJKV1QiLCJhbGciOiIgIn0.eyJzdWIiOiJUZXN0In0.17DlZn0zeYhz3uTQCRpSx9hYlUj1SJxDMeZLof8dSHw",
"eyJ0eXAiOiJKV1QiLCJhbGciOiIgICAgIn0.eyJzdWIiOiJUZXN0In0.17DlZn0zeYhz3uTQCRpSx9hYlUj1SJxDMeZLof8dSHw",
"eyJ0eXAiOiJKV1QiLCJhbGciOm51bGx9.eyJzdWIiOiJUZXN0In0.17DlZn0zeYhz3uTQCRpSx9hYlUj1SJxDMeZLof8dSHw",
"eyJ0eXAiOiJKV1QiLCJhbGciOjQ0OH0.eyJzdWIiOiJUZXN0In0.17DlZn0zeYhz3uTQCRpSx9hYlUj1SJxDMeZLof8dSHw",
"eyJ0eXAiOiJKV1QiLCJhbGciOltdfQ.eyJzdWIiOiJUZXN0In0.17DlZn0zeYhz3uTQCRpSx9hYlUj1SJxDMeZLof8dSHw",
"eyJ0eXAiOiJKV1QiLCJhbGciOnt9fQ.eyJzdWIiOiJUZXN0In0.17DlZn0zeYhz3uTQCRpSx9hYlUj1SJxDMeZLof8dSHw",
// Payload not JSON object
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.bnVsbA.17DlZn0zeYhz3uTQCRpSx9hYlUj1SJxDMeZLof8dSHw",
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.NDQ4.17DlZn0zeYhz3uTQCRpSx9hYlUj1SJxDMeZLof8dSHw",
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.InNhdW5hIg.17DlZn0zeYhz3uTQCRpSx9hYlUj1SJxDMeZLof8dSHw",
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.W10.17DlZn0zeYhz3uTQCRpSx9hYlUj1SJxDMeZLof8dSH"
);
}

Expand Down

0 comments on commit a196e5a

Please sign in to comment.