Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: linkcodes and preauthsessionids should not use padding #825

Merged
merged 4 commits into from
Oct 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres
to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [unreleased]
## [7.0.1] - 2023-10-04

- Remove padding from link codes and pre-auth session ids in passwordless, but keep support for old format that included padding (`=` signs)

## [7.0.0] - 2023-09-19

Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ compileTestJava { options.encoding = "UTF-8" }
// }
//}

version = "7.0.0"
version = "7.0.1"


repositories {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ public static ConsumeCodeResponse consumeCode(TenantIdentifierWithStorage tenant
linkCodeHash = parsedDeviceId.getLinkCode(linkCodeSalt, userInputCode).getHash();
}

if (!deviceIdHash.encode().equals(deviceIdHashFromUser)) {
if (!deviceIdHash.encode().equals(deviceIdHashFromUser.replaceAll("=", ""))) {
throw new DeviceIdHashMismatchException();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public class PasswordlessDeviceIdHash {
public PasswordlessDeviceIdHash(byte[] bytes) {
// We never do anything further with the bytes, so we can just encode, store and reuse it.
// If we choose to do storage based on bytes this can change.
this.encodedValue = Base64.getUrlEncoder().encodeToString(bytes);
this.encodedValue = Base64.getUrlEncoder().encodeToString(bytes).replaceAll("=", "");
}

public PasswordlessDeviceIdHash(String encodedValue) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public static PasswordlessLinkCode decodeString(String linkCode) throws Base64En
}

public String encode() {
return Base64.getUrlEncoder().encodeToString(bytes);
return Base64.getUrlEncoder().encodeToString(bytes).replaceAll("=", "");
}

public PasswordlessLinkCodeHash getHash() throws NoSuchAlgorithmException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,81 @@ public void testConsumeLinkCode() throws Exception {
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED));
}

/**
* success without existing user - link code with equal signs removed
*
* @throws Exception
*/
@Test
public void testConsumeLinkCodeWithoutEqualSigns() throws Exception {
String[] args = {"../"};

TestingProcessManager.TestingProcess process = TestingProcessManager.start(args);
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED));

if (StorageLayer.getStorage(process.getProcess()).getType() != STORAGE_TYPE.SQL) {
return;
}

PasswordlessStorage storage = (PasswordlessStorage) StorageLayer.getStorage(process.getProcess());

Passwordless.CreateCodeResponse createCodeResponse = Passwordless.createCode(process.getProcess(), EMAIL, null,
null, null);
assertNotNull(createCodeResponse);

assert(!createCodeResponse.deviceIdHash.contains("="));
assert(!createCodeResponse.linkCode.contains("="));

long consumeStart = System.currentTimeMillis();
Passwordless.ConsumeCodeResponse consumeCodeResponse = Passwordless.consumeCode(process.getProcess(), null,
createCodeResponse.deviceIdHash, null, createCodeResponse.linkCode);

assertNotNull(consumeCodeResponse);
checkUserWithConsumeResponse(storage, consumeCodeResponse, EMAIL, null, consumeStart);

PasswordlessDevice[] devices = storage.getDevicesByEmail(new TenantIdentifier(null, null, null), EMAIL);
assertEquals(0, devices.length);

process.kill();
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED));
}

/**
* success without existing user - link code with equal signs (padding)
*
* @throws Exception
*/
@Test
public void testConsumeLinkCodeWithEqualSigns() throws Exception {
String[] args = {"../"};

TestingProcessManager.TestingProcess process = TestingProcessManager.start(args);
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED));

if (StorageLayer.getStorage(process.getProcess()).getType() != STORAGE_TYPE.SQL) {
return;
}

PasswordlessStorage storage = (PasswordlessStorage) StorageLayer.getStorage(process.getProcess());

Passwordless.CreateCodeResponse createCodeResponse = Passwordless.createCode(process.getProcess(), EMAIL, null,
null, null);
assertNotNull(createCodeResponse);

long consumeStart = System.currentTimeMillis();
Passwordless.ConsumeCodeResponse consumeCodeResponse = Passwordless.consumeCode(process.getProcess(), null,
createCodeResponse.deviceIdHash + "=", null, createCodeResponse.linkCode + "=");

assertNotNull(consumeCodeResponse);
checkUserWithConsumeResponse(storage, consumeCodeResponse, EMAIL, null, consumeStart);

PasswordlessDevice[] devices = storage.getDevicesByEmail(new TenantIdentifier(null, null, null), EMAIL);
assertEquals(0, devices.length);

process.kill();
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED));
}

/**
* Success without existing user - input code
*
Expand Down
Loading