Skip to content

Commit

Permalink
Merge branch 'fapi1final-RP-changes' into 'master'
Browse files Browse the repository at this point in the history
Add FAPI1 Advanced RP tests, initial version

See merge request openid/conformance-suite!989
  • Loading branch information
jogu committed Jun 8, 2021
2 parents cdd9283 + 0bc9608 commit dee8609
Show file tree
Hide file tree
Showing 71 changed files with 1,695 additions and 261 deletions.
12 changes: 11 additions & 1 deletion .gitlab-ci/expected-failures-client.json
Original file line number Diff line number Diff line change
@@ -1 +1,11 @@
[]
[
{
"test-name": "fapi1-advanced-final-client-test-invalid-scope-in-token-endpoint-response",
"variant": "*",
"configuration-filename": "automated-ob-client-test*.json",
"current-block": "",
"condition": "fapi1-advanced-final-client-test-invalid-scope-in-token-endpoint-response",
"expected-result": "failure",
"comment": "The client does not support fapi1 final yet"
}
]
16 changes: 12 additions & 4 deletions .gitlab-ci/run-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,21 @@ makeClientTest() {
. node-client-setup.sh
. node-core-client-setup.sh

# client FAPI1-ADVANCED
TESTS="${TESTS} fapi1-advanced-final-client-test-plan[client_auth_type=private_key_jwt][fapi_profile=plain_fapi][fapi_auth_request_method=by_value][fapi_response_mode=plain_response][fapi_jarm_type=oidc] automated-ob-client-test.json"
TESTS="${TESTS} fapi1-advanced-final-client-test-plan[client_auth_type=mtls][fapi_profile=plain_fapi][fapi_auth_request_method=pushed][fapi_response_mode=jarm][fapi_jarm_type=oidc] automated-ob-client-test.json"
#TESTS="${TESTS} fapi1-advanced-final-client-test-plan[client_auth_type=mtls][fapi_profile=plain_fapi][fapi_auth_request_method=pushed][fapi_response_mode=plain_response][fapi_jarm_type=oidc] automated-ob-client-test.json"
#TESTS="${TESTS} fapi1-advanced-final-client-test-plan[client_auth_type=private_key_jwt][fapi_profile=plain_fapi][fapi_auth_request_method=by_value][fapi_response_mode=jarm][fapi_jarm_type=oidc] automated-ob-client-test.json"
TESTS="${TESTS} fapi1-advanced-final-client-test-plan[client_auth_type=private_key_jwt][fapi_profile=plain_fapi][fapi_auth_request_method=by_value][fapi_response_mode=jarm][fapi_jarm_type=plain_oauth] automated-ob-client-test-no-openid-scope.json"


# client FAPI-RW-ID2
TESTS="${TESTS} fapi-rw-id2-client-test-plan[client_auth_type=private_key_jwt][fapi_profile=plain_fapi] automated-ob-client-test.json"
TESTS="${TESTS} fapi-rw-id2-client-test-plan[client_auth_type=mtls][fapi_profile=plain_fapi] automated-ob-client-test.json"
TESTS="${TESTS} fapi-rw-id2-client-test-plan[client_auth_type=private_key_jwt][fapi_profile=plain_fapi][fapi_auth_request_method=by_value][fapi_response_mode=plain_response][fapi_jarm_type=oidc] automated-ob-client-test.json"
TESTS="${TESTS} fapi-rw-id2-client-test-plan[client_auth_type=mtls][fapi_profile=plain_fapi][fapi_auth_request_method=by_value][fapi_response_mode=plain_response][fapi_jarm_type=oidc] automated-ob-client-test.json"

# client FAPI-RW-ID2-OB
TESTS="${TESTS} fapi-rw-id2-client-test-plan[client_auth_type=private_key_jwt][fapi_profile=openbanking_uk] automated-ob-client-test.json"
TESTS="${TESTS} fapi-rw-id2-client-test-plan[client_auth_type=mtls][fapi_profile=openbanking_uk] automated-ob-client-test.json"
TESTS="${TESTS} fapi-rw-id2-client-test-plan[client_auth_type=private_key_jwt][fapi_profile=openbanking_uk][fapi_auth_request_method=by_value][fapi_response_mode=plain_response][fapi_jarm_type=oidc] automated-ob-client-test.json"
TESTS="${TESTS} fapi-rw-id2-client-test-plan[client_auth_type=mtls][fapi_profile=openbanking_uk][fapi_auth_request_method=by_value][fapi_response_mode=plain_response][fapi_jarm_type=oidc] automated-ob-client-test.json"

# client OpenID Connect Core Client Tests
TESTS="${TESTS} oidcc-client-test-plan(../conformance-suite/.gitlab-ci/oidcc-rp-tests-config.json) automated-oidcc-client-test.json"
Expand Down
22 changes: 20 additions & 2 deletions scripts/run-test-plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,16 +217,34 @@ def run_test_plan(test_plan, config_file, output_dir):
state = conformance.wait_for_state(module_id, ["WAITING", "FINISHED"])

if state == "WAITING":
# If it's a client test, we need to run the client
if re.match(r'(fapi-rw-id2(-ob)?-client-.*)', module):
# If it's a client test, we need to run the client.
# please note oidcc client tests are handled in a separate method. only FAPI ones will reach here
if re.match(r'fapi-rw-id2-client-.*', module) or \
re.match(r'fapi1-advanced-final-client-.*', module):
print("FAPI client test: " + module + " " + json.dumps(variant))
profile = variant['fapi_profile']
os.putenv('CLIENTTESTMODE', 'fapi-ob' if re.match(r'openbanking', profile) else 'fapi-rw')
os.environ['ISSUER'] = os.environ["CONFORMANCE_SERVER"] + os.environ["TEST_CONFIG_ALIAS"]
if 'fapi_auth_request_method' in variant.keys() and variant['fapi_auth_request_method']:
os.environ['FAPI_AUTH_REQUEST_METHOD'] = variant['fapi_auth_request_method']
else:
os.environ['FAPI_AUTH_REQUEST_METHOD'] = 'by_value'
if 'fapi_response_mode' in variant.keys() and variant['fapi_response_mode']:
os.environ['FAPI_RESPONSE_MODE'] = variant['fapi_response_mode']
else:
os.environ['FAPI_RESPONSE_MODE'] = 'plain_response'
if 'fapi_jarm_type' in variant.keys() and variant['fapi_jarm_type']:
os.environ['FAPI_JARM_TYPE'] = variant['fapi_jarm_type']
else:
os.environ['FAPI_JARM_TYPE'] = 'oidc'

os.environ['TEST_MODULE_NAME'] = module
subprocess.call(["npm", "run", "client"], cwd="./sample-openbanking-client-nodejs")

conformance.wait_for_state(module_id, ["FINISHED"])

except Exception as e:
traceback.print_exc()
print('Exception: Test {} failed to run to completion: {}'.format(module_with_variants, e))
if module_id != '':
test_time_taken[module_id] = time.time() - test_start_time
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package net.openid.conformance.condition.as;

import com.google.common.base.Strings;
import com.google.gson.JsonObject;
import com.nimbusds.jose.JOSEException;
import net.openid.conformance.condition.AbstractCondition;
import net.openid.conformance.condition.PostEnvironment;
import net.openid.conformance.condition.PreEnvironment;
import net.openid.conformance.testmodule.Environment;
import net.openid.conformance.util.JWTUtil;

import java.text.ParseException;

public abstract class AbstractExtractRequestObject extends AbstractCondition {

public Environment processRequestObjectString(String requestObjectString, Environment env) {

if (Strings.isNullOrEmpty(requestObjectString)) {
throw error("Could not find request object in request parameters");
}

try {
JsonObject client = env.getObject("client");
JsonObject serverEncKeys = env.getObject("server_encryption_keys");
JsonObject jsonObjectForJwt = JWTUtil.jwtStringToJsonObjectForEnvironment(requestObjectString, client, serverEncKeys);

if(jsonObjectForJwt==null) {
throw error("Couldn't extract request object", args("request", requestObjectString));
}
env.putObject("authorization_request_object", jsonObjectForJwt);

logSuccess("Parsed request object", args("request_object", jsonObjectForJwt));

return env;

} catch (ParseException e) {
throw error("Couldn't parse request object", e, args("request", requestObjectString));
} catch (JOSEException e) {
throw error("Request object decryption failed", e, args("request", requestObjectString));
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ public String encrypt(String stringToBeEncrypted, String clientSecret, JsonObjec
//id_token_encrypted_response_enc
// OPTIONAL. JWE enc algorithm [JWA] REQUIRED for encrypting the ID Token issued to this Client.
// If id_token_encrypted_response_alg is specified, the default for this value is A128CBC-HS256.
//Also for JARM:
// ...If authorization_encrypted_response_alg is specified, the default for this value is A128CBC-HS256...
EncryptionMethod encryptionMethod = EncryptionMethod.A128CBC_HS256;
if(enc!=null) {
encryptionMethod = EncryptionMethod.parse(enc);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package net.openid.conformance.condition.as;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import net.openid.conformance.condition.AbstractCondition;
import net.openid.conformance.condition.PostEnvironment;
import net.openid.conformance.condition.PreEnvironment;
import net.openid.conformance.testmodule.Environment;

public class AddAuthorizationSigningAlgValuesSupportedToServerConfiguration extends AbstractCondition {

@Override
@PreEnvironment(required = {"server"}, strings = "signing_algorithm")
@PostEnvironment(required = "server")
public Environment evaluate(Environment env) {
String alg = env.getString("signing_algorithm");
JsonArray data = new JsonArray();
data.add(alg);

JsonObject server = env.getObject("server");
server.add("authorization_signing_alg_values_supported", data);

logSuccess("Added authorization_signing_alg_values_supported to server configuration",
args ("alg_values", data));
return env;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package net.openid.conformance.condition.as;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import net.openid.conformance.condition.AbstractCondition;
import net.openid.conformance.condition.PostEnvironment;
import net.openid.conformance.condition.PreEnvironment;
import net.openid.conformance.testmodule.Environment;

public class AddJARMResponseModeToServerConfiguration extends AbstractCondition {

@Override
@PreEnvironment(required = "server")
@PostEnvironment(required = "server")
public Environment evaluate(Environment env) {

JsonArray data = new JsonArray();
data.add("jwt");

JsonObject server = env.getObject("server");
server.add("response_modes_supported", data);

logSuccess("Added jwt as response_modes_supported", args ("response_modes_supported", data));

return env;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package net.openid.conformance.condition.as;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import net.openid.conformance.condition.AbstractCondition;
import net.openid.conformance.condition.PostEnvironment;
import net.openid.conformance.condition.PreEnvironment;
import net.openid.conformance.testmodule.Environment;

public class AddResponseTypeCodeToServerConfiguration extends AbstractCondition {

@Override
@PreEnvironment(required = "server")
@PostEnvironment(required = "server")
public Environment evaluate(Environment env) {

JsonArray data = new JsonArray();
data.add("code");

JsonObject server = env.getObject("server");
server.add("response_types_supported", data);

logSuccess("Added code as response type supported", args ("response_types_supported", data));

return env;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package net.openid.conformance.condition.as;

import com.google.gson.JsonObject;
import net.openid.conformance.condition.AbstractCondition;
import net.openid.conformance.condition.PostEnvironment;
import net.openid.conformance.condition.PreEnvironment;
import net.openid.conformance.runner.TestDispatcher;
import net.openid.conformance.testmodule.Environment;
import net.openid.conformance.testmodule.OIDFJSON;

public class ChangeIdTokenEncryptedResponseAlgToRSA15 extends AbstractCondition {

@Override
@PreEnvironment(required = "client")
@PostEnvironment(required = "client")
public Environment evaluate(Environment env) {
JsonObject client = env.getObject("client");
client.addProperty("id_token_encrypted_response_alg", "RSA1_5");
log("Changed id_token_encrypted_response_alg to RSA1_5");
return env;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public Environment evaluate(Environment env) {

JsonObject authzEndpointReqParams = env.getObject("authorization_endpoint_http_request_params");
JsonObject effective = authzEndpointReqParams.deepCopy();
effective.remove("request_uri");

//override request parameters if authorization_request_object exists
if(env.containsObject("authorization_request_object")) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package net.openid.conformance.condition.as;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import net.openid.conformance.condition.PostEnvironment;
import net.openid.conformance.condition.PreEnvironment;
import net.openid.conformance.testmodule.Environment;

public class EncryptJARMResponse extends AbstractJWEEncryptStringToClient
{

@Override
@PreEnvironment(strings = "jarm_response", required = "client")
@PostEnvironment(strings = "jarm_response")
public Environment evaluate(Environment env) {

String response = env.getString("jarm_response");
String alg = env.getString("client", "authorization_encrypted_response_alg");
String enc = env.getString("client", "authorization_encrypted_response_enc");
String clientSecret = env.getString("client", "client_secret");
//client jwks may be null
JsonElement clientJwksElement = env.getElementFromObject("client", "jwks");
JsonObject clientJwks = null;
if(clientJwksElement!=null) {
clientJwks = clientJwksElement.getAsJsonObject();
}

String encryptedResponse = encrypt(response, clientSecret, clientJwks, alg, enc,
"authorization_encrypted_response_alg", "authorization_encrypted_response_enc");

log("Encrypted the JARM response", args("response", encryptedResponse,
"authorization_encrypted_response_alg", alg,
"authorization_encrypted_response_enc", enc));
env.putString("jarm_response", encryptedResponse);
return env;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* MUST always be passed using the OAuth 2.0 request syntax containing the openid scope
* value to indicate to the underlying OAuth 2.0 logic that this is an OpenID Connect request.
*/
public class OIDCCEnsureAuthorizationHttpRequestContainsOpenIDScope extends AbstractCondition {
public class EnsureAuthorizationHttpRequestContainsOpenIDScope extends AbstractCondition {

@Override
@PreEnvironment(required = {"authorization_endpoint_http_request_params"})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ public Environment evaluate(Environment env) {
for (String claim : params.keySet()) {
// make sure every claim in the "params" input is included in the request object

// don't count the "request" param itself
if (claim.equals("request")) {
// skip "request" and "request_uri"
if (claim.equals("request") || claim.equals("request_uri")) {
continue;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package net.openid.conformance.condition.as;

import com.google.common.base.Strings;
import net.openid.conformance.condition.AbstractCondition;
import net.openid.conformance.condition.PreEnvironment;
import net.openid.conformance.testmodule.Environment;

public class EnsureAuthorizationRequestContainsStateParameter extends AbstractCondition {

@Override
@PreEnvironment(required = CreateEffectiveAuthorizationRequestParameters.ENV_KEY)
public Environment evaluate(Environment env) {
String state = env.getString(CreateEffectiveAuthorizationRequestParameters.ENV_KEY, CreateEffectiveAuthorizationRequestParameters.STATE);
if (Strings.isNullOrEmpty(state)) {
throw error("Missing state parameter");
} else {
logSuccess("Found state parameter", args("state", state));
return env;
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package net.openid.conformance.condition.as;

import net.openid.conformance.condition.AbstractCondition;
import net.openid.conformance.condition.PreEnvironment;
import net.openid.conformance.testmodule.Environment;

public class EnsureClientIdInAuthorizationRequestParametersMatchRequestObject extends AbstractCondition {

@Override
@PreEnvironment(required = {"authorization_endpoint_http_request_params", "authorization_request_object"})
public Environment evaluate(Environment env) {
String requestParam = env.getString("authorization_endpoint_http_request_params", "client_id");
String requestObjectValue = env.getString("authorization_request_object", "claims.client_id");
if(requestParam==null) {
throw error("client_id not found in http request parameters");
}
if(!requestParam.equals(requestObjectValue)) {
throw error("client_id in http request parameters does not match client_id in request object",
args("http_request_value", requestParam, "request_object_value", requestObjectValue));
}
logSuccess("client_id http request parameter value matches client_id in request object");
return env;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package net.openid.conformance.condition.as;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import net.openid.conformance.condition.AbstractCondition;
import net.openid.conformance.condition.PostEnvironment;
import net.openid.conformance.condition.PreEnvironment;
import net.openid.conformance.testmodule.Environment;

public class EnsureIdTokenEncryptedResponseAlgIsNotRSA1_5 extends AbstractCondition {

@Override
@PreEnvironment(required = "client")
public Environment evaluate(Environment env) {
String alg = env.getString("client", "id_token_encrypted_response_alg");
if("RSA1_5".equals(alg)) {
throw error("RSA1_5 is not allowed");
}
logSuccess("Id token encryption algorithm is not RSA1_5", args("alg", alg));
return env;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* Use this condition for logging a WARNING only
* Normally this condition should never lead to a failure
*/
public class OIDCCEnsureOptionalAuthorizationRequestParametersMatchRequestObject extends AbstractCondition {
public class EnsureOptionalAuthorizationRequestParametersMatchRequestObject extends AbstractCondition {

@Override
@PreEnvironment(required = {"authorization_endpoint_http_request_params", "authorization_request_object"})
Expand All @@ -26,7 +26,7 @@ public Environment evaluate(Environment env) {
Map<String, Object> argsForLog = new HashMap<>();

for (String paramName : authzEndpointReqParams.keySet()) {
if(OIDCCEnsureRequiredAuthorizationRequestParametersMatchRequestObject.parametersThatMustMatch.contains(paramName)) {
if(EnsureRequiredAuthorizationRequestParametersMatchRequestObject.parametersThatMustMatch.contains(paramName)) {
//these should be already checked. checking again would cause duplicate logs
continue;
}
Expand Down
Loading

0 comments on commit dee8609

Please sign in to comment.