Se você quiser gerar um JWT a partir de um certificado/chave x509, qualquer operação (inclusive leitura) em %SYS.X509Credentials exige permissão U no recurso %Admin_Secure. O %Admin_Secure é necessário porque %SYS.X509Credentials é persistente e foi implementado dessa forma para impedir que todos os usuários tenham acesso às chaves privadas.
Se o recurso %Admin_Secure não estiver disponível em tempo de execução, você pode usar a seguinte alternativa.
Ao revisar o código de geração de JWT, descobri que o código de JWT utiliza %SYS.X509Credentials apenas como fonte de dados em tempo de execução para PrivateKey, PrivateKeyPassword, e Certificate. Como alternativa, você pode usar uma implementação não persistente da interface X.509 em tempo de execução, expondo apenas essas propriedades.Se você estiver usando interoperabilidade, o certificado/chave privada (Cert/PK) pode ser armazenado em credenciais para acesso seguro.
Class User.X509 Extends %RegisteredObject
{
Property PrivateKey As %VarString
Property PrivateKeyPassword As %String
Property Certificate As %VarString
Property HasPrivateKey As %Boolean [ InitialExpression = {$$$YES} ]
ClassMethod GetX509() As User.X509
{
set x509 = ..%New()
set x509.PrivateKey = ..Key()
set x509.Certificate = ..Cert()
quit x509
}
ClassMethod GetX509FromCredential(credential) As User.X509
{
set credentialObj = ##class(Ens.Config.Credentials).%OpenId(credential,,.sc)
throw:$$$ISERR(sc) ##class(%Exception.StatusException).ThrowIfInterrupt(sc)
set x509 = ..%New()
set x509.PrivateKey = credentialObj.Password
set x509.Certificate = credentialObj.Username
quit x509
}
ClassMethod Key()
{
q "-----BEGIN RSA PRIVATE KEY-----"_$C(13,10)
_"YOUR_TEST_KEY"_$C(13,10)
_"-----END RSA PRIVATE KEY-----"
}
ClassMethod Cert() As %VarString
{
q "-----BEGIN CERTIFICATE-----"_$C(13,10)
_"YOUR_TEST_CERT"_$C(13,10)
_"-----END CERTIFICATE-----"
}
}
E você pode gerar o JWT da seguinte forma:
ClassMethod JWT() As %Status
{
Set sc = $$$OK
Set x509 = ##class(User.X509).GetX509()
Set algorithm ="RS256"
Set header = {"alg": (algorithm), "typ": "JWT"}
Set claims= {"Key": "Value" }
#
Set sc = ##class(%Net.JSON.JWK).CreateX509(algorithm,x509,.privateJWK)
If $$$ISERR(sc) {
Write $SYSTEM.OBJ.DisplayError(sc)
}
#
Set sc = ##class(%Net.JSON.JWKS).PutJWK(privateJWK,.privateJWKS)
If $$$ISERR(sc) {
Write $SYSTEM.OBJ.DisplayError(sc)
}
Set sc = ##Class(%Net.JSON.JWT).Create(header,,claims,privateJWKS,,.pJWT)
If $$$ISERR(sc) {
Write $SYSTEM.OBJ.DisplayError(sc)
}
Write pJWT
Return sc
}
Como alternativa, você pode usar um objeto dinâmico para evitar a criação de uma classe; nesse caso, ficaria assim:
ClassMethod JWT(credential) As %Status
{
Set sc = $$$OK
Set credentialObj = ##class(Ens.Config.Credentials).%OpenId(credential,,.sc)
throw:$$$ISERR(sc) ##class(%Exception.StatusException).ThrowIfInterrupt(sc)
Set x509 = {
"HasPrivateKey": true,
"PrivateKey": (credentialObj.Password),
"PrivateKeyPassword":"",
"Certificate":(credentialObj.Username)
}
Set algorithm ="RS256"
Set header = {"alg": (algorithm), "typ": "JWT"}
Set claims= {"Key": "Value" }
#
Set sc = ##class(%Net.JSON.JWK).CreateX509(algorithm,x509,.privateJWK)
If $$$ISERR(sc) {
Write $SYSTEM.OBJ.DisplayError(sc)
}
#
Set sc = ##class(%Net.JSON.JWKS).PutJWK(privateJWK,.privateJWKS)
If $$$ISERR(sc) {
Write $SYSTEM.OBJ.DisplayError(sc)
}
Set sc = ##Class(%Net.JSON.JWT).Create(header,,claims,privateJWKS,,.pJWT)
If $$$ISERR(sc) {
Write $SYSTEM.OBJ.DisplayError(sc)
}
Write pJWT
Return sc
}