Jwt list of audience in Spring - spring

When creating the token, I've set a list of audience as follows:
JwtClaims claims = new JwtClaims();
claims.setIssuer(issuer);
claims.setAudience(Lists.newArrayList(audiences));
claims.setExpirationTimeMinutesInTheFuture(60);
claims.setJwtId(keyId);
claims.setIssuedAtToNow();
claims.setNotBeforeMinutesInThePast(2);
claims.setSubject(subject);
The problem comes on the consumer side that is not giving me the expected audience.
This is what I've done on the consumer side:
JwtConsumer jwtConsumer = new JwtConsumerBuilder()
.setRequireExpirationTime()
.setAllowedClockSkewInSeconds(30)
.setRequireSubject()
.setExpectedIssuer(issuer)
.setExpectedAudience(String.valueOf(Lists.newArrayList(audiences)))
.setVerificationKey(rsaJsonWebKey.getKey())
.build();
There's something wrong with the setExpectedAudience but I can't find the problem. This is what I got in the console.
Invalid JWT! org.jose4j.jwt.consumer.InvalidJwtException: JWT (claims->{"iss":"EXAMPLEISSUER","aud":["test1","test2","test3"],"exp":1657880599,"jti":"EXAMPLE_SHA1withRSA","iat":1657876999,"nbf":1657876879,"sub":"example"}) rejected due to invalid claims or other invalid content. Additional details: [[8] Audience (aud) claim [test1, test2, test3] doesn't contain an acceptable identifier. Expected [test1, test2, test3] as an aud value.]

setExpectedAudience() accepts varargs, so make an ordinary String[] array
from your audiences and use it as an argument.

Related

How to read query parameter with ^ in the URL

I'm trying to implement a callback endpoint for eBay. This endpoint is called by eBay to hand the application a user token.
I can define my endpoint as expected
http://localhost:8080/api/ebay/auth
Nothing unusual here. My enpoint looks like this, really basic:
#RestController
#RequestMapping(path = ["/api/ebay/auth"])
class EbayAuthController {
#GetMapping(path = [""])
fun getAccessToken(#RequestParam code: String) {
println("Auth code: $code")
}
}
Now eBay passes the parameter code with the value
?code=v^1.1%23i^1%23r^1%23p^3%23I^3%23f^0%23t^[excluded_user_token]&expires_in=299
When I call my endpoint with this data set, it returns 400 Bad Request. I can reproduce this by adding ^ to any request. I read it's an unsafe character to use - but the issue is: Ebay uses this character to return the user token, so I must read it.
When I pass a sample with http://localhost:8080/api/ebay/auth?code=123 it prints the code as expected.
I've never encountered that problem, can anyone help me or point me in the right direction how to solve this?
According to this answer by Dirk Deyne to the question Spring-boot controller error when url contains braces character, you can specify server.tomcat.relaxed-query-chars in your application.properties:
server.tomcat.relaxed-query-chars=^

Can "token" generated using "Paseto Token" be decrypted and viewed like "JWT Token"?

I am using "Platform agnostic Security Token" for oAuth in Golang - https://github.com/o1egl/paseto
I am not able to understand, why this is better than JWT even after reading README
My Major Question is:
Can "token" generated be altered like "JWT" and pass modified or tampered data?
Can "token" generated using "paseto" be decrypted and viewed like "JWT"?
Paseto library above uses "SET" and "GET" method inside their JSONToken method. Is that how we can verify authenticity of the user?
Sample Code:
symmetricKey := []byte("YELLOW SUBMARINE, BLACK WIZARDRY") // Must be 32 bytes
now := time.Now()
exp := now.Add(24 * time.Hour)
nbt := now
jsonToken := paseto.JSONToken{
Audience: "test",
Issuer: "test_service",
Jti: "123",
Subject: "test_subject",
IssuedAt: now,
Expiration: exp,
NotBefore: nbt,
}
// Add custom claim to the token
jsonToken.Set("data", "this is a signed message")
footer := "some footer"
v2 := paseto.NewV2()
// Encrypt data
token, err := v2.Encrypt(symmetricKey, jsonToken, footer)
// token = "v2.local.E42A2iMY9SaZVzt-WkCi45_aebky4vbSUJsfG45OcanamwXwieieMjSjUkgsyZzlbYt82miN1xD-X0zEIhLK_RhWUPLZc9nC0shmkkkHS5Exj2zTpdNWhrC5KJRyUrI0cupc5qrctuREFLAvdCgwZBjh1QSgBX74V631fzl1IErGBgnt2LV1aij5W3hw9cXv4gtm_jSwsfee9HZcCE0sgUgAvklJCDO__8v_fTY7i_Regp5ZPa7h0X0m3yf0n4OXY9PRplunUpD9uEsXJ_MTF5gSFR3qE29eCHbJtRt0FFl81x-GCsQ9H9701TzEjGehCC6Bhw.c29tZSBmb290ZXI"
// Decrypt data
var newJsonToken paseto.JSONToken
var newFooter string
err := v2.Decrypt(token, symmetricKey, &newJsonToken, &newFooter)
Now, if you see there is code: jsonToken.Set("data", "this is a signed message") and we can get that value in Decrypt data at the end where newJsonToken variable is created.
We can get the value of "data" key using: newJsonToken.Get("data").
But is above data "verifiable" and can't be tampered or modified on user's end?
Like in JWT debugger at JWT.io, People can tamper data and know the algorithm and pass "modified" data.
Can user do the same with my generated token as well? Can they decode and pass tampered data? or they can't decode data or view actual data at all?
1 - Can "token" generated be altered like "JWT" and pass modified or tampered data?
Note that token cannot be "altered" either using PASETO or JWT without knowing the signing key (which should of course be secret).
The fact you mention about being able to view the JWT token data in JWT.io page is because data is not encrypted (so you can see it without the key).
But token is signed, so if you modify any value and don't have the key, you won't be able to sign it back and the token receiver will note the token is not valid when trying to verify it.
2 - Can "token" generated using "paseto" be decrypted and viewed like "JWT"?
It depends on how you generate the PASETO token.
See here:
https://tools.ietf.org/id/draft-paragon-paseto-rfc-00.html#rfc.section.2
Format for the token is version.purpose.payload.
And from the docs:
The payload is a string that contains the token's data. In a local token, this data is encrypted with a symmetric cipher. In a public token, this data is unencrypted.
So if you generate the token as in the code snippet you posted (local token, with a symmetric key), then payload will be encrypted (you won't be able to see it unless you know the symmetric key and use that one to decrypt it).
If you use a public/private key pair, then payload will not be encrypted, so you'll be able to see it without the key (but you'll not be able to change it and sign it again without knowing the private key).

Unable to pass Header Authorization in JMeter. Facing unauthorizedError

I'm running Performance test in JMeter where I have to pass Authorization details using Header Manager.
Here is my code:
String headerName = "Authorization";
String headerValue = "Basic MyKey MyValue";
Header bcHeader = new Header(headerName,headerValue);
HeaderManager hm = new HeaderManager();
hm.setProperty(TestElement.TEST_CLASS, HeaderManager.class.getName());
hm.add(bcHeader);
hm.add(new Header("Content-Type", "application/json"));
hm.add(new Header("Access-Control-Allow-Origin", "*"));
And I'm facing UnAuthorized error.
Please let me know if there is another way to write the code.
Thanks.
Normally you should be using HTTP Authorization Manager in order to bypass Basic HTTP Auth challenge.
However if you're going to manually construct Authorization header be aware that it should have the following form
Name: Authorization
Value: Basic
After Basic you need to provide username and password separated by colon and encoded into Base64. So if your username is MyKey and password is MyValue you should encode the string MyKey:MyValue and add the result to the header so it would look like:
Basic TXlLZXk6TXlWYWx1ZQ==
When it comes to Java code it would be something like:
String headerName = "Authorization";
String username = "MyKey";
String password = "MyValue";
Header bcHeader = new Header(headerName,
"Basic " +
Base64.encodeBase64String((username + ":" + password).getBytes(StandardCharsets.UTF_8)));
HeaderManager hm = new HeaderManager();
hm.add(bcHeader);
hm.add(new Header("Content-Type", "application/json"));
hm.add(new Header("Access-Control-Allow-Origin", "*"));
hm.setName(JMeterUtils.getResString("header_manager_title"));
hm.setProperty(TestElement.TEST_CLASS, HeaderManager.class.getName());
hm.setProperty(TestElement.GUI_CLASS, HeaderPanel.class.getName());
If you are getting authorization header value somewhere in your response you can extract and dynamic values and apply correlations to the script.
Here is what you have to do. Extract Authorization header value using regular expressions and store it in a jmeter variable lets assuem you have saved it as Auth .
Add a header manager (Right click on thread group -->config element--> Header manager) according to jmeter scoping rules.
Use ${variablename} and replace the hard coded header value with ${variablename} ,as we saved it in Auth variable you can use ${Auth}.
You can add headers to header manager click on add and give header name and value as shown below
i'm getting authorization value in request 1's reponse as shown below
so to extract this add a regular expression extractor to the same request (request 1) as shown below.
Now we can use ${Auth} in header manager , add header manager to request 2 and give header name and values as shown below
you can see in the results authorization has passed its value
For more information on Extracting variables please follow this link
Let me know if it helps

Documenting Mutually Exclusive Query Parameters in API Blueprint

I'm documenting a public API that has a method named /findGuild that takes a mandatory key parameter and one of the following parameters:
byPlayer
byName
It must have either byPlayer or byName; My question is: How do I indicate that byPlayer and byName are mutually exclusive, but one is mandatory?
Right now, I have the following in my .apib for this Resource:
### GET /findGuild{?byName,byPlayer,key}
+ Parameters
+ byName: `YourGuild` (string, optional) - Search for the Guild by its name.
+ byPlayer: (string, optional) - Search for Guild by a player. Does not seem to work.
+ key: `ffffffff-ffff-ffff-ffff-ffffffffffff` (string, required) - The user's API key.
+ Response 200 (application/json)
+ Attributes (object)
+ guild (string) - The guild id or null.
+ success (boolean) - Should be true.
+ Body
{
"guild": "ffffffffffffffffffffffff",
"success": true
}
I am afraid (but not totally sure) API Blueprint is not capable of expressing this kind of relationship at the moment.
What I can surely tell you is that, according to public roadmap, URI Parameters will be replaced with an MSON object, which supports the scenario you're asking for.
Hope it helps!

paste and use a oauth2 access token

I have an application using ruby and sinatra. I want to be able to paste a token which is in this format:
{"access_token":"token...uwD--Of0ikNjr8AeW3oS9zP2rith3fdsf2Wk","token_type":"Bearer","expires_in":3600,"created":1415727521}
into a text-area and use it. Now the problem is, the pasted token is in string format. I have tried converting it into an hash and also to json format but it ain't working still.
Here is my code:
post '/tokenize' do
got_token = params[:token] # the pasted token
token_hash = JSON.parse(got_token) #I am not sure if I did this correctly.but it is producing an hash.
token = token_hash.to_json # producing the token in json format as the original token that I pasted.
get_contacts(JSON.parse(token)) # calling the function that should use the token. giving an error since it is not a valid oauth token.
redirect to ("/tokenize/finish")
end
Error: It is producing an error because the token is not a valid oauth token.
Someone please tell me how I make the token valid and usable.
You can manually instantiate token class OAuth2::AccessToken with params that you have collected full definition of that constructour you can find here.
But eventually you will need OAuth2 client for using that manually instantiated.
For example:
client = OAuth2::Client.new('client_id', 'client_secret', :site => 'https://example.org')
token = OAuth2::AccessToken.new(client, collected_token, collected_opts)
response = token.get('/api/resource', :params => { 'query_foo' => 'bar' })

Resources