-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[MCC-750736]support mauth-protocol-test-suite (#133)
- Loading branch information
1 parent
7e5d49c
commit 74f3cd1
Showing
14 changed files
with
487 additions
and
2 deletions.
There are no files selected for viewing
This file contains 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 characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[submodule "mauth-protocol-test-suite"] | ||
path = mauth-protocol-test-suite | ||
url = https://github.com/mdsol/mauth-protocol-test-suite.git |
This file contains 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 characters
This file contains 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 characters
This file contains 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 characters
Submodule mauth-protocol-test-suite
added at
303bf5
115 changes: 115 additions & 0 deletions
115
...les/mauth-authenticator-scala/src/test/scala/com/mdsol/mauth/MauthProtocolSuiteSpec.scala
This file contains 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 characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
package com.mdsol.mauth | ||
|
||
import java.util.UUID | ||
|
||
import com.mdsol.mauth.test.utils.model._ | ||
import com.mdsol.mauth.test.utils.ProtocolTestSuiteHelper | ||
import com.mdsol.mauth.util.MAuthKeysHelper.getPrivateKeyFromString | ||
import com.mdsol.mauth.util.{EpochTimeProvider, MAuthKeysHelper, MAuthSignatureHelper} | ||
import com.mdsol.mauth.utils.ClientPublicKeyProvider | ||
import org.scalamock.scalatest.MockFactory | ||
import org.scalatest.BeforeAndAfterAll | ||
import org.scalatest.flatspec.AnyFlatSpec | ||
import org.scalatest.matchers.should.Matchers | ||
|
||
import scala.jdk.CollectionConverters._ | ||
|
||
class MauthProtocolSuiteSpec extends AnyFlatSpec with BeforeAndAfterAll with Matchers with MockFactory { | ||
|
||
val REQUEST_VALIDATION_TIMEOUT_SECONDS: Long = 300L | ||
val mockClientPublicKeyProvider: ClientPublicKeyProvider = mock[ClientPublicKeyProvider] | ||
val mockEpochTimeProvider: EpochTimeProvider = mock[EpochTimeProvider] | ||
val authenticatorV2: RequestAuthenticator = | ||
new RequestAuthenticator(mockClientPublicKeyProvider, REQUEST_VALIDATION_TIMEOUT_SECONDS, mockEpochTimeProvider, true) | ||
|
||
behavior of "MauthProtocolSuiteSpec" | ||
|
||
val signingConfig = ProtocolTestSuiteHelper.SIGNING_CONFIG | ||
if (signingConfig == null) { | ||
fail("Signing Configuration is not available.") | ||
} | ||
|
||
if (ProtocolTestSuiteHelper.PUBLIC_KEY == null) { | ||
fail("Public Key is not available.") | ||
} | ||
|
||
val publicKey = MAuthKeysHelper.getPublicKeyFromString(ProtocolTestSuiteHelper.PUBLIC_KEY) | ||
val uuid = UUID.fromString(signingConfig.getAppUuid) | ||
val privateKey = getPrivateKeyFromString(signingConfig.getPrivateKey) | ||
val mAuthSigner = new DefaultSigner(uuid, privateKey, mockEpochTimeProvider, java.util.Arrays.asList(MAuthVersion.MWSV2)) | ||
|
||
// run the tests | ||
val testSpecifications = ProtocolTestSuiteHelper.TEST_SPECIFICATIONS | ||
testSpecifications.foreach { testSpec => | ||
testSpec.getType match { | ||
case CaseType.AUTHENTICATION_ONLY => | ||
val authenticationOnly = testSpec.asInstanceOf[AuthenticationOnly] | ||
s"Test Case: ${authenticationOnly.getName}" should "pass authentication" in { | ||
doAuthentication( | ||
authenticationOnly.getUnsignedRequest, | ||
authenticationOnly.getAuthenticationHeader | ||
) shouldBe true | ||
} | ||
|
||
case CaseType.SIGNING_AUTHENTICATION => | ||
val signingAuthentication = testSpec.asInstanceOf[SigningAuthentication] | ||
val authHeader = signingAuthentication.getAuthenticationHeader | ||
val unsignedRequest = signingAuthentication.getUnsignedRequest | ||
|
||
val httpVerb = unsignedRequest.getHttpVerb | ||
val resourcePath = unsignedRequest.getResourcePath | ||
val queryString = unsignedRequest.getQueryString | ||
val bodyInBytes = unsignedRequest.getBodyInBytes | ||
s"Test Case: ${signingAuthentication.getName}" should "correctly generate the string to sign" in { | ||
MAuthSignatureHelper.generateStringToSignV2( | ||
uuid, | ||
httpVerb, | ||
resourcePath, | ||
queryString, | ||
bodyInBytes, | ||
signingConfig.getRequestTime | ||
) shouldBe signingAuthentication.getStringToSign | ||
} | ||
|
||
it should "correctly generate the signature" in { | ||
MAuthSignatureHelper.encryptSignatureRSA( | ||
privateKey, | ||
signingAuthentication.getStringToSign | ||
) shouldBe signingAuthentication.getSignature | ||
} | ||
|
||
it should "correctly generate the authentication headers" in { | ||
(mockEpochTimeProvider.inSeconds _: () => Long).expects().returns(signingConfig.getRequestTime.toLong) | ||
val headers: Map[String, String] = | ||
mAuthSigner | ||
.generateRequestHeaders(httpVerb, resourcePath, bodyInBytes, queryString) | ||
.asScala | ||
.toMap | ||
headers(MAuthRequest.MCC_AUTHENTICATION_HEADER_NAME) shouldBe authHeader.getMccAuthentication | ||
headers(MAuthRequest.MCC_TIME_HEADER_NAME) shouldBe authHeader.getMccTime.toString | ||
} | ||
|
||
it should "pass authentication" in { | ||
doAuthentication(unsignedRequest, authHeader) shouldBe true | ||
} | ||
} | ||
} | ||
|
||
private def doAuthentication(unsignedRequest: UnsignedRequest, authHeader: AuthenticationHeader): Boolean = { | ||
val mauthRequest = MAuthRequest.Builder.get | ||
.withAuthenticationHeaderValue(authHeader.getMccAuthentication) | ||
.withTimeHeaderValue(String.valueOf(authHeader.getMccTime)) | ||
.withHttpMethod(unsignedRequest.getHttpVerb) | ||
.withResourcePath(unsignedRequest.getResourcePath) | ||
.withQueryParameters(unsignedRequest.getQueryString) | ||
.withMessagePayload(unsignedRequest.getBodyInBytes) | ||
.build() | ||
|
||
(mockEpochTimeProvider.inSeconds _: () => Long).expects().returns(signingConfig.getRequestTime.toLong + 3) | ||
(mockClientPublicKeyProvider.getPublicKey _) | ||
.expects(uuid) | ||
.returns(publicKey) | ||
authenticatorV2.authenticate(mauthRequest) | ||
} | ||
|
||
} |
159 changes: 159 additions & 0 deletions
159
...es/mauth-test-utils/src/main/java/com/mdsol/mauth/test/utils/ProtocolTestSuiteHelper.java
This file contains 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 characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
package com.mdsol.mauth.test.utils; | ||
|
||
import com.mdsol.mauth.test.utils.model.AuthenticationHeader; | ||
import com.mdsol.mauth.test.utils.model.AuthenticationOnly; | ||
import com.mdsol.mauth.test.utils.model.SigningAuthentication; | ||
import com.mdsol.mauth.test.utils.model.SigningConfig; | ||
import com.mdsol.mauth.test.utils.model.TestCase; | ||
import com.mdsol.mauth.test.utils.model.UnsignedRequest; | ||
|
||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
|
||
import java.io.File; | ||
import java.io.FilenameFilter; | ||
import java.io.IOException; | ||
import java.nio.charset.Charset; | ||
import java.nio.charset.StandardCharsets; | ||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
import java.nio.file.Paths; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
public class ProtocolTestSuiteHelper { | ||
|
||
final static String TEST_SUITE_RELATIVE_PATH = "../../mauth-protocol-test-suite/"; | ||
final static String MWSV2_TEST_CASE_PATH = getFullFilePath("protocols/MWSV2/"); | ||
|
||
public final static SigningConfig SIGNING_CONFIG; | ||
static { | ||
SigningConfig tmp = null; | ||
String configFile = getFullFilePath("signing-config.json"); | ||
try { | ||
ObjectMapper objectMapper = new ObjectMapper(); | ||
byte[] jsonData = Files.readAllBytes(normalizePath(configFile)); | ||
tmp = objectMapper.readValue(jsonData, SigningConfig.class); | ||
} catch (IOException ex) { | ||
throw new IllegalStateException("Failed to load the config file " + configFile, ex); | ||
} | ||
SIGNING_CONFIG = tmp; | ||
} | ||
|
||
public final static String PUBLIC_KEY ; | ||
static { | ||
String tmp = null; | ||
String filePath = getFullFilePath("signing-params/rsa-key-pub"); | ||
try { | ||
tmp = new String(Files.readAllBytes(normalizePath(filePath)), StandardCharsets.UTF_8); | ||
} catch (IOException ex) { | ||
throw new IllegalStateException("Failed to load the public key " + filePath, ex); | ||
} | ||
PUBLIC_KEY = tmp; | ||
} | ||
|
||
public final static TestCase[] TEST_SPECIFICATIONS; | ||
static { | ||
List<TestCase> testCaseList = new ArrayList<TestCase>(); | ||
String[] cases = retrieveV2TestCases(); | ||
|
||
for (String caseName : cases) { | ||
String caseFile = caseName.concat("/").concat(caseName); | ||
AuthenticationHeader authHeader = loadAuthenticationHeader(caseFile.concat(".authz")); | ||
UnsignedRequest unsignedRequest = loadUnsignedRequest(caseFile.concat(".req")); | ||
byte[] bodyInBytes = getTestRequestBody(unsignedRequest, caseName); | ||
unsignedRequest.setBodyInBytes(bodyInBytes); | ||
|
||
boolean isAuthenticationOnly = caseName.contains("authentication-only"); | ||
if(isAuthenticationOnly) { | ||
testCaseList.add(new AuthenticationOnly(caseName, unsignedRequest, authHeader)); | ||
} else { | ||
String stringToSign = loadTestDataAsString(caseFile.concat(".sts")); | ||
String signature = loadTestDataAsString(caseFile.concat(".sig")); | ||
testCaseList.add(new SigningAuthentication(caseName, unsignedRequest, authHeader, stringToSign, signature)); | ||
} | ||
} | ||
TEST_SPECIFICATIONS = testCaseList.toArray(new TestCase[0]); | ||
} | ||
|
||
public static String loadPrivateKey(String keyFile) { | ||
String privateKey = ""; | ||
Path filePath = normalizePath(getFullFilePath(keyFile)); | ||
try { | ||
privateKey = new String(Files.readAllBytes(filePath), Charset.defaultCharset()); | ||
} catch (IOException ex) { | ||
throw new IllegalStateException("Failed to load the private key " + filePath, ex); | ||
} | ||
return privateKey; | ||
} | ||
|
||
private static String[] retrieveV2TestCases() { | ||
File file = new File(MWSV2_TEST_CASE_PATH); | ||
String[] directories = file.list(new FilenameFilter() { | ||
@Override | ||
public boolean accept(File current, String name) { | ||
return new File(current, name).isDirectory(); | ||
} | ||
}); | ||
return directories; | ||
} | ||
|
||
private static byte[] loadTestData(String filePath) { | ||
byte[] bytes = {}; | ||
Path path = normalizePath(MWSV2_TEST_CASE_PATH + filePath); | ||
try { | ||
bytes = Files.readAllBytes(path); | ||
} catch (IOException ex) { | ||
throw new IllegalStateException("Failed to load " + filePath, ex); | ||
} | ||
return bytes; | ||
} | ||
|
||
private static String loadTestDataAsString(String filePath) { | ||
byte[] bytes = loadTestData(filePath); | ||
return bytes.length==0 ? "" : new String(bytes, Charset.defaultCharset()); | ||
} | ||
|
||
private static UnsignedRequest loadUnsignedRequest(String filePath) { | ||
UnsignedRequest unsignedRequest = new UnsignedRequest(); | ||
byte[] jsonData = loadTestData(filePath); | ||
try { | ||
ObjectMapper objectMapper = new ObjectMapper(); | ||
unsignedRequest = objectMapper.readValue(jsonData, UnsignedRequest.class); | ||
} catch (IOException ex) { | ||
throw new IllegalStateException("Failed to load " + filePath, ex); | ||
} | ||
return unsignedRequest; | ||
} | ||
|
||
private static byte[] getTestRequestBody(UnsignedRequest unsignedRequest, String caseName) { | ||
byte[] bytes = new byte[0]; | ||
if (unsignedRequest.getBodyFilepath() != null) { | ||
String bodyFile = caseName.concat("/").concat(unsignedRequest.getBodyFilepath()); | ||
bytes = ProtocolTestSuiteHelper.loadTestData(bodyFile); | ||
} | ||
else if (unsignedRequest.getHttpVerb() != null) { | ||
bytes = unsignedRequest.getBody().getBytes(StandardCharsets.UTF_8); | ||
} | ||
return bytes; | ||
} | ||
|
||
private static AuthenticationHeader loadAuthenticationHeader(String filePath) { | ||
AuthenticationHeader authenticationHeader = new AuthenticationHeader(); | ||
byte[] jsonData = loadTestData(filePath); | ||
try { | ||
ObjectMapper objectMapper = new ObjectMapper(); | ||
authenticationHeader = objectMapper.readValue(jsonData, AuthenticationHeader.class); | ||
} catch (IOException ex) { | ||
throw new IllegalStateException("Failed to load " + filePath, ex); | ||
} | ||
return authenticationHeader; | ||
} | ||
|
||
private static Path normalizePath(String filepath) { | ||
return Paths.get(filepath).normalize(); | ||
} | ||
|
||
private static String getFullFilePath(String filePath) { | ||
return TEST_SUITE_RELATIVE_PATH + filePath; | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
...mauth-test-utils/src/main/java/com/mdsol/mauth/test/utils/model/AuthenticationHeader.java
This file contains 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 characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package com.mdsol.mauth.test.utils.model; | ||
|
||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
|
||
public class AuthenticationHeader { | ||
@JsonProperty("MCC-Authentication") | ||
String mccAuthentication; | ||
@JsonProperty("MCC-Time") | ||
Long mccTime; | ||
|
||
public String getMccAuthentication() { return mccAuthentication; } | ||
|
||
public void setMccAuthentication(String mccAuthentication) { this.mccAuthentication = mccAuthentication; } | ||
|
||
public long getMccTime() { return mccTime; } | ||
|
||
public void setMccTime(Long mccTime) { this.mccTime = mccTime; } | ||
} |
30 changes: 30 additions & 0 deletions
30
...s/mauth-test-utils/src/main/java/com/mdsol/mauth/test/utils/model/AuthenticationOnly.java
This file contains 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 characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package com.mdsol.mauth.test.utils.model; | ||
|
||
public class AuthenticationOnly implements TestCase { | ||
String name; | ||
AuthenticationHeader authHeader; | ||
UnsignedRequest unsignedRequest; | ||
|
||
public AuthenticationOnly( | ||
String name, | ||
UnsignedRequest unsignedRequest, | ||
AuthenticationHeader authHeader) { | ||
this.name = name; | ||
this.unsignedRequest = unsignedRequest; | ||
this.authHeader = authHeader; | ||
} | ||
|
||
@Override | ||
public String getName() { return name; } | ||
|
||
@Override | ||
public CaseType getType() { return CaseType.AUTHENTICATION_ONLY; } | ||
|
||
public UnsignedRequest getUnsignedRequest() { return unsignedRequest; } | ||
|
||
public void setUnsignedRequest(UnsignedRequest unsignedRequest) { this.unsignedRequest = unsignedRequest; } | ||
|
||
public AuthenticationHeader getAuthenticationHeader() { return authHeader; } | ||
|
||
public void setAuthenticationHeader(AuthenticationHeader authHeader) { this.authHeader = authHeader; } | ||
} |
6 changes: 6 additions & 0 deletions
6
modules/mauth-test-utils/src/main/java/com/mdsol/mauth/test/utils/model/CaseType.java
This file contains 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 characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package com.mdsol.mauth.test.utils.model; | ||
|
||
public enum CaseType { | ||
AUTHENTICATION_ONLY, | ||
SIGNING_AUTHENTICATION | ||
} |
Oops, something went wrong.