Open ppazos opened 8 years ago
Dear @pabloalba @Alotor @mgdelacroix @burtbeckwith can you give some feedback about this issue?
Thanks a lot!
I've checked this and what I think we should do is provide extension methods for CryptoService
Then you'll be able to change the default behaviour easily. You'll need to create a new class that extends CryptoService
and override the getSecret method to use your own logic instead of using a configuration parameter.
What do you think? Would be this enough?
@Alotor I think that should be enough if we can get the request.securityStatelessMap from the service that will extend CryptoService, because the secretKey will depend on information associated with the user, contained in the token payload. Is that possible?
I think that would need the plugin to parse the token payload before validating the token (don't know how it is currently done), I mean:
Does it sound reasonable?
@Alotor @pabloalba any comments on ^?
I will try to accomplish this next week since I need it in my project: https://github.com/ppazos/cabolabs-ehrserver/issues/450
Since my app is multi-tenant, I don't want tokens from different organizations of be verified using the same "secret", but have a "secret" per organization.
Hi @ppazos,
First, I apologize for not answering your queries. I'll try to be more over things from now on.
I understand what you're trying to achieve.
You need to extend JwtStatelessTokenProvider
so the generateToken
adds the organization and encrypt the token using your custom keys and validateAndExtractToken
reads your token and decrypt with your custom keys.
Changes that will be required in the plugin:
validateAndExtractToken
into two methods validateToken
and extractTokenData
. This way you can use the data from extractTokenData
into validateToken
and read your company dataWhen the above is done, you can implement your "MultiTentant" custom provider like:
class CustomJwtStatelessTokenProvider implements StatelessTokenProvider {
Map<String, String> customKeys
Integer expirationTime
@Override
void init(Integer expirationTime) {
this.expirationTime = expirationTime
}
private getCompanyTokenProvider(String company) {
def companyKey = customKeys[company]
def companyCS = new CryptoService()
companyCS.init(companyKey)
def jwtProvider = new JwtStatelessTokenProvider()
jwtProvider.init(this.expirationTime)
jwtProvider.cryptoService = companyCS
}
@Override
String generateToken(String userName, String salt=null, Map<String,String> extraData=[:]) {
def company = extraData["company"]
def jwtProvider = getCompanyTokenProvider(company)
return jwtProvider.generateToken(userName, salt, extraData)
}
@Override
Map extractToken(String token) {
return TokenUtils.parseTokenData(token)
}
@Override
void validateToken(String token, Map<String, String> extraData=[:]) {
def company = extraData["company"]
def jwtProvider = getCompanyTokenProvider(company)
jwtProvider.validateToken(token, extraData)
}
}
What do you think? Will this be enough?
@Alotor awesome! thanks for the detailed guide. I will try to implement this and get back to you if I have any issues. I'll send my changes to the plugin as a PR.
About the extraData, I my idea was to put the organization UID there, so I can get the organization by UID before validating the token, and get the "secret" from the organization, to validate the token (I don't want to use the org UID as "secret" because it is public, the "secret" would be an private API key or something like that... an UID).
One small question, where/how should I inject my implementation of the StatelessTokenProvider so the plugin takes my custom provider instead of the default one?
Thanks again!
Right now the secret key is configured globally in Config.groovy
I have a requirement of validating tokens generated externally, using a secret key that I provide. Those keys are generated for different users of the app, and provider to them (it is an API key).
My users will generate JWT using that key, and send the JWT on every request. Since I have the key, and receive the token, I want to validate it.
Is it possible to tell the security stateless plugin which private key to use dynamically to not use the global one from Config.groovy?
Thanks