Jose4j: Unable to find a suitable verification key for JWS w/ header - jose4j

The verification fails because key_ops does not meet the criteria of the SimpleJwkFilter created from static method filterForInboundSigned(JsonWebSignature jws) in SelectorSupport. The public key looks something like this:
{
"kid": "xxx",
"use": "sig",
"key_ops": [
"sign"
],
"kty": "xxx",
"e": "xxx",
"n": "xxx"
}
According to the SimpleJwkFilter "key_ops" either has to be null or contain the value "verify" to match the criteria.
Is there some way to customize this behaviour in jose4j? Maybe skip validation of "key_ops"?

If you're using HttpsJwksVerificationKeyResolver, you could have simple little subclass of HttpsJwks which unsets the "key_ops" on each JWK before the filter sees them. That'd look something like this:
class MyHttpsJwks extends HttpsJwks
{
public MyHttpsJwks(String location)
{
super(location);
}
#Override
public List<JsonWebKey> getJsonWebKeys() throws JoseException, IOException
{
List<JsonWebKey> jsonWebKeys = super.getJsonWebKeys();
for (JsonWebKey jwk : jsonWebKeys)
{
jwk.setKeyOps(null);
}
return jsonWebKeys;
}
}
And then instantiate the resolver like new HttpsJwksVerificationKeyResolver(new MyHttpsJwks("https://bad.example.com/jwks"));
If you're using JwksVerificationKeyResolver, you can just do the same kind thing to the JsonWebKey list before instantiating the resolver with it. Similar preprocessing on the list will also work, if you are using VerificationJwkSelector or the SimpleJwkFilter directly.
FWIW, according to RFC7517 the "use" and "key_ops" parameters shouldn't be used together and if they are, they are supposed to convey the same meaning. I would argue that the JWK in question isn't honoring that because the "key_ops" of "sign" says the key can be used to compute a digital signature while a "use" of "sig" says that the key can be used for digital signature operations in general (sign or verify).

Related

Return type of transaction?

I'm running chaincode-java from fabric-samples.
#Transaction(intent = Transaction.TYPE.EVALUATE)
public ArrayList<Asset> GetAllAssets(final Context ctx) {
ChaincodeStub stub = ctx.getStub();
ArrayList<Asset> queryResults = new ArrayList<Asset>();
// To retrieve all assets from the ledger use getStateByRange with empty startKey & endKey.
// Giving empty startKey & endKey is interpreted as all the keys from beginning to end.
// As another example, if you use startKey = 'asset0', endKey = 'asset9' ,
// then getStateByRange will retrieve asset with keys between asset0 (inclusive) and asset9 (exclusive) in lexical order.
QueryResultsIterator<KeyValue> results = stub.getStateByRange("", "");
for (KeyValue result: results) {
Asset asset = genson.deserialize(result.getStringValue(), Asset.class);
System.out.println(asset);
queryResults.add(asset);
}
// final String response = genson.serialize(queryResults);
return queryResults;
}
The GetAllAssets() method was returning String, but I changed it to ArrayList.
As a result, GetAllAssets throws error when invoked.
$ peer chaincode query -C mychannel -n basic -c '{"Args":["GetAllAssets"]}'
Error: endorsement failure during query. response: status:500 message:"Unexpected error"
The log says
Thread[fabric-txinvoke:2,5,main] 11:15:01:224 INFO org.hyperledger.fabric.contract.ContractRouter processRequest Got invoke routing request
Thread[fabric-txinvoke:2,5,main] 11:15:01:226 INFO org.hyperledger.fabric.contract.ContractRouter processRequest Got the invoke request for:GetAllAssets []
Thread[fabric-txinvoke:2,5,main] 11:15:01:234 INFO org.hyperledger.fabric.contract.ContractRouter processRequest Got routing:GetAllAssets:org.hyperledger.fabric.samples.assettransfer.AssetTransfer
Thread[fabric-txinvoke:2,5,main] 11:15:01:274 SEVERE org.hyperledger.fabric.Logger error nulljava.lang.NullPointerException
at org.hyperledger.fabric.contract.execution.JSONTransactionSerializer.toBuffer(JSONTransactionSerializer.java:84)
at org.hyperledger.fabric.contract.execution.impl.ContractExecutionService.convertReturn(ContractExecutionService.java:89)
at org.hyperledger.fabric.contract.execution.impl.ContractExecutionService.executeRequest(ContractExecutionService.java:67)
at org.hyperledger.fabric.contract.ContractRouter.processRequest(ContractRouter.java:123)
at org.hyperledger.fabric.contract.ContractRouter.invoke(ContractRouter.java:134)
at org.hyperledger.fabric.shim.impl.ChaincodeInvocationTask.call(ChaincodeInvocationTask.java:106)
at org.hyperledger.fabric.shim.impl.InvocationTaskManager.lambda$newTask$17(InvocationTaskManager.java:265)
at java.base/java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1736)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
Thread[fabric-txinvoke:2,5,main] 11:15:01:276 SEVERE org.hyperledger.fabric.shim.impl.ChaincodeInvocationTask call [13733a23] Invoke failed with error code 500. Sending ERROR
Can I return List from a transaction? Besides String, what other types can I return? Is there any documentation that I can take a look?
Bit of background first; the ContractAPI that is available in Java, Go and Typescript is used to generate a 'model' of the overall contract including the data type that be passed and returned from transaction functions. (JavaScript supports a limited subset to the extent possible based on it's typing).
In order to support this there has to be a 'serializer' of some sort to process the data. The underlying chaincode API of just 'invoke(byte[]): byte[]' gives the developer the power to serialize how they wish though not all of us need to use that power.
There is a default 'serializer' in the ContractAPI; this can be swapped out if needed.
To specifically answer the question;
The return types can be:
strings,
numbers (for Java this is any of the primitive 'number' types)
booleans,
other types that have been annotated.
arrays of the above
For the 'other types', there are annotations that can be used to define types that can also be passed to and from the transaction functions.
You might see something like this:
#DataType()
public final class Complex {
#Property()
private final String id;
#Property()
private final Description description;
#Property()
private final int value;
public String getID() {
return id;
}
public int getValue() {
return value;
}
public Description getDescription(){
return description;
}
}
Description there is also a class annotated in a similar manner.
This would produce the Contract Metadata that would look like
"Description": {
"$id": "Description",
"type": "object",
"properties": {
"colour": {
"type": "string"
},
"owners": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"Complex": {
"$id": "Complex",
"type": "object",
"properties": {
"id": {
"type": "string"
},
"value": {
"type": "number"
},
"description": {
"$ref": "Description"
}
}
}
On the Contract Model, or Contract Metadata
There is a JSON schema for this at
https://github.com/hyperledger/fabric-chaincode-node/blob/main/apis/fabric-contract-api/schema/contract-schema.json
Isn't this restrictive? what about Lists?
It's a fair comment, from a Java perspective, something like an ArrayList or Map would be a reasonable thing to return. However the challenge is that it is possible for the contracts to be implemented in different languages. Plus once deployed the Contract will be running for some time, therefore the metadata provides a strong 'API Definition' between the Smart Contract and the Client Application.
What transaction functions (also in the metadata) will be clearly defined.
Summary
I would like to provide some more examples (and docs!) but wanted to get this written up first. There are extensions and changes we could make, and would like to make but there are only so many hours!
As a maintainer of these repos, we'd love to have people come on board if this is an area of interest.

Can't get CollectionField to work in EasyAdmin 3.0

I am trying to use "Tags" in my Account Entity.
So
I have Entity "Account"
I have Entity "Tag"
In "Account" Entity, I have
/**
* #ORM\ManyToMany(targetEntity=Tag::class, inversedBy="accounts")
* #ORM\JoinTable(name="account_tag")
*/
private $tags;
In "Tag" entity I have
/**
* #ORM\ManyToMany(targetEntity=Account::class, mappedBy="tags")
*/
private $accounts;
In my AccountCrudController => ConfigureFields, I use "CollectionField" for my "tags" property
public function configureFields(string $pageName): iterable
{
return [
TextField::new('name'),
AssociationField::new('owner'),
AssociationField::new('parent'),
CollectionField::new('tags'),
];
}
I am getting below
[Expected value of type "App\Entity\Tag" for association field "App\Entity\Account#$tags", got "string" instead.1
You should be able to use an AssociationField here as well, which would fit your purpose.
AssociationField::new('tags') will allow you to reference existing Tags.
If you wish to create all new Tags together, you could use something like this as there is no way to add Tags on the fly in the AssociationField at the moment.
Have you tried setting your CollectionField like this:
CollectionField::new('tags')
->allowAdd()
->allowDelete()
->setEntryType(TagType::class)
;
The important part is the TagType where you define your own FormType. I am also trying to implement this feature, so if you have a fully working example, let us know!
public function configureFields(string $pageName): iterable
{
return [
TextField::new('name'),
AssociationField::new('owner'),
AssociationField::new('parent'),
CollectionField::new('tags')
->SetEntryType(Tag::class)
];
}

The performance issue of validating entity using value object

I have the following value object code which validates CustCode by some expensive database operations.
public class CustCode : ValueObject<CustCode>
{
private CustCode(string code) { Value = code; }
public static Result<CustCode> Create(string code)
{
if (string.IsNullOrWhiteSpace(code))
return Result.Failure<CustCode>("Code should not be empty");
// validate if the value is still valid against the database. Expensive and slow
if (!ValidateDB(code)) // Or web api calls
return Result.Failure<CustCode>("Database validation failed.");
return Result.Success<CustCode>(new CustCode(code));
}
public string Value { get; }
// other methods omitted ...
}
public class MyEntity
{
CustCode CustCode { get; }
....
It works fine when there is only one or a few entity instances with the type. However, it becomes very slow for method like GetAll() which returns a lot of entities with the type.
public async IAsyncEnumerable<MyEntity> GetAll()
{
string line;
using var sr = File.OpenText(_config.FileName);
while ((line = await sr.ReadLineAsync()) != null)
{
yield return new MyEntity(CustCode.Create(line).Value); // CustCode.Create called many times
}
}
Since data in the file was already validated before saving so it's actually not necessary to be validated again. Should another Create function which doesn't validate the value to be created? What's the DDD idiomatically way to do this?
I generally attempt not to have the domain call out to retrieve any additional data. Everything the domain needs to do its job should be passed in.
Since value objects represent immutable state it stands to reason that once it has managed to be created the values are fine. To this end perhaps the initial database validation can be performed in the integration/application "layer" and then the CustCode is created using only the value(s) provided.
Just wanted to add an additional point to #Eben Roux answer:
In many cases the validation result from a database query is dependent on when you run the query.
For example when you want to check if a phone number exists or if some product is in stock. The answers to those querys can change any second, and though are not suited to allow or prevent the creation of a value object.
You may create a "valid" object, that is (unknowingly) becoming invalid in the very next second (or the other way around). So why bother running an expensive validation, if the validation result is not reliable.

Hamcrest closeTo not working in RestAssured.body()

I have a test that I cannot get the syntax correctly:
#Test
void statsTest() {
given().queryParam("param", "ball")
.when().get()
.then().body("total", is(closeTo(10.0, 0.1*10.0))));
}
However, the test keeps failing even though the condition is met:
java.lang.AssertionError: 1 expectation failed.
JSON path total doesn't match.
Expected: is a numeric value within <1.0> of <10.0>
Actual: 10
I've never had a problem with types before in this setup of RestAssured and Hamcrest. For example, a test of the sort: body("total", greaterThan(9)) works fine, which means that there is some type casting under the hood.
I've looked through the docs and cannot find a way to cast the value of body("total") to a numerical value.
so I suspect that this is a bug or I'm not understanding something here.
Here's the JSON response. I had to clip it to make is short. Hope this works.
{
"stats": {
"totalHits": 1,
"searchEngineTimeInMillis": 83,
"searchEngineRoundTripTimeInMillis": 87,
"searchProcessingTimeInMillis": 101
},
"products": {
"id": "total",
"displayName": "Documents",
"ball": 10}
}
The key value pair corresponding to key: "total" in your response seems to be of integer type. So it needs to be checked for bounds with integer based bounds (1,10). So instead of using the closeTo matcher, you can use the following matcher.
allOf(greaterThanOrEqualTo(1), lessThanOrEqualTo(10)))
I've put together another approach that solves the problem but with a slightly different approach. Much thanks to those who populate the web with their code samples. The following assumes you already have set the base URI and PATH. You can add a path deeper in the response by using the get("/path..."). This answer assumes a JSON type response.
private static Response getResponse(String paramName, String paramValue) {
return given().queryParam(paramName, paramValue)
.when().get();
}
public static String getJsonValue(String jsonPath, String paramName, String paramValue) {
Response response = getResponse(paramName, paramValue);
//response.getBody().prettyPrint();
JsonPath jsonPathEvaluator = response.jsonPath();
return jsonPathEvaluator.get(jsonPath).toString();
}
You can simply print the return value and cast it to the type you need.
The test then looks like this:
public static void checkIfNumberCloseToValue(String jsonPath,
String paramName,
String paramValue,
Double error,
Double expected) {
Double value = Double.valueOf(Utils.getJsonValue(jsonPath, paramName, paramValue));
double range = expected * error;
assertThat(value, closeTo(expected, range));
}

The test failure message for mockito verify

For a parameter class
class Criteria {
private Map params;
public getMap(){ return params; }
}
and a service method accept this criteria
class Service{
public List<Person> query(Criteria criteria){ ... }
}
A custom featureMatcher is used to match the criteria key
private Matcher<Criteria> hasCriteria(final String key, final Matcher<?> valueMatcher){
return new FeatureMatcher<Criteria, Object>((Matcher<? super Object>)valueMatcher, key, key){
#Override protected Object featureValueOf(Criteria actual){
return actual.getMap().get(key);
}
}
}
when using mockito to veryify the arguments:
verify(Service).query((Criteria) argThat("id", hasCriteria("id", equalTo(new Long(12)))));
The error message shows that:
Argument(s) are different! Wanted:
Service.query(
id <12L>
);
-> at app.TestTarget.test_id (TestTarget.java:134)
Actual invocation has different arguments:
Service.query(
app.Criteria#509f5011
);
If I use ArugmentCaptor,
ArgumentCaptor<Criteria> argument = ArgumentCaptor.forClass(Criteria.class);
verify(Service).query(argument.capture());
assertThat(argument.getValue(), hasCriteria("id", equalTo(new Long(12))));
The message is much better:
Expected: id <12L> but id was <2L>
How can I get such message, without using ArgumentCaptor?
The short answer is to adjust the Criteria code, if it's under your control, to write a better toString method. Otherwise, you may be better off using the ArgumentCaptor method.
Why is it hard to do without ArgumentCaptor? You know you're expecting one call, but Mockito was designed to handle it even if you have a dozen similar calls to evaluate. Even though you're using the same matcher implementation, with the same helpful describeMismatch implementation, assertThat inherently tries once to match where verify sees a mismatch and keeps trying to match any other call.
Consider this:
// in code:
dependency.call(true, false);
dependency.call(false, true);
dependency.call(false, false);
// in test:
verify(mockDependency).call(
argThat(is(equalTo(true))),
argThat(is(equalTo(true))));
Here, Mockito wouldn't know which of the calls was supposed to be call(true, true); any of the three might have been it. Instead, it only knows that there was a verification you were expecting that was never satisfied, and that one of three related calls might have been close. In your code with ArgumentCaptor, you can use your knowledge that there's only one call, and provide a more-sane error message; for Mockito, the best it can do is to output all the calls it DID receive, and without a helpful toString output for your Criteria, that's not very helpful at all.

Resources