massenz / jwt-opa Goto Github PK
View Code? Open in Web Editor NEWSpring Boot (reactive) Integration with Open Policy Agent (OPA)
License: Apache License 2.0
Spring Boot (reactive) Integration with Open Policy Agent (OPA)
License: Apache License 2.0
The GH Action to build the library fails, it should be fixed.
It is a spurious error:
A problem occurred evaluating project ':jwt-opa'.
> Could not get unknown property 'ossrhUsername' for Credentials [username: null] of type org.gradle.internal.credentials.DefaultPasswordCredentials_Decorated.
it is due to the credentials for Maven Central publish not being (correctly) available in the repository; we need to find a way to prevent the failure during the build/test process.
Currently the routes
configuration does an exact match against the URI path - this should be changed to suppor either RegEx or Ant matchers, so that something like this is possible:
routes:
authorized:
- "/users/*/accounts/**"
- ...
This would also be necessary to support #11
The format of JWTs created by the JwtTokenProvider
class is somewhat inflexible, in that it only allows to specify the username
(sub
field) and expiresAt
(exp
field).
There may be situations in which the application may want to carry additional information in the Token, so we should augment the ability to specify those (possibly as a set of {key, value}
pairs).
We need to implement a KeypairLoader
and SecretsResolver
that supports a Vault store (alongside with the necessary configurations to connect to it, including the secret/permissions).
In the run-server
script, there should be a POST
to the OPA container to enable the default policy
It would often be useful, to evaluate an authorization policy, to inspect the body of the request and make assertions against certain fields' values.
Adding a body
element to the OPA request (the relevant code is in the OpaReactiveAuthorizationManager
class) is not as straightforward as it would appear.
There are a couple of issues:
While the former problem could be solved naively (just ignore any request whose Content-Length
is greater than a given, configurable threshold) and the latter could be left as a "problem for the reader" (in this case, the Rego policy author(s)), we choose here a different approach:
body
element (object) to the TokenBasedAuthorizationRequest
if the ContentType
is application/json
;body
string if ContentType
is text/*
;ContentType
will be added to the headers
section (see #36).The design currently assumes that the application will provide user management and authentication (eg, via username/password)
It would be great to have support and direct integration for OAuth2 servers, using Spring Security facilities.
The data in the DB is correct
This is about creating a simple Dockerfile
to build webapp
as a container (and, possibly, add it to the compose.yaml
)
We currently publish "fat" JARs, including all dependencies (most notably Spring Framework).
Quite apart from being bad practice and making the artifacts unnecessarily bloated, this prevents applications that import our JAR to correctly import code/sources and navigate to them in IDEs.
Our published JAR should only contain our code, and there should be clear documentation as to what additional imports are needed (including correct version information).
The webapp-example
demo application only brushes the surface of what is possible with jwt-opa
and also has a lot of unnecessary "other stuff" that is no longer relevant.
It should be updated with a couple of "interesting" use cases and also to better showcase the usage of jwt-opa
; it is also apparent that a number of other supporting activities are necessary to use the library proficiently (eg, configuring the OPA server, designing Rego policies): those should be added too, or at least documented.
Use the arc42 template
https://www.workingsoftware.dev/software-architecture-documentation-the-ultimate-guide/
java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
We currently have a single opa.policy.rule
configuration; this is not flexible enough.
Ideally, API endpoints should be "grouped" under distinct rule endpoints, and such groups be configurable.
This could be done in the routes.authorized
configuration, by grouping the routes under OPA authorization control in "groups" and each point having a distinct opa.policy.rule
configuration:
opa:
policy: kapsules/rules
routes:
...
authorized:
users:
rule: "users-auth"
endpoints:
- /users/**
- /users/*/accounts
orders:
rule: "orders"
endpoints:
- /orders/**
- /users/*/orders/**
- ...
We want to provide a simple example of how to run a service that uses JWT-OPA on a Kubernetes cluster as a Pod, via a Helm chart.
If a user is already authenticated (typically, it has entered the password in a browser window) we get this error:
2022-01-20 22:04:38.686 ERROR 29783 --- [oundedElastic-3] c.a.o.s.OpaReactiveAuthorizationManager : Unexpected user not authenticated, or Authentication type (UsernamePasswordAuthenticationToken) not an instance of ApiTokenAuthentication, cannot progress authorization
(this happens while using the OpenAPI documentation pages, for example)
We should still try and authorize the request, if the API Token is present.
Should be discussed whether to generate a fresh JWT if the auth is valid.
Currently KeyMaterialConfiguration
assumes that keypair
property must be non-null and it has two attributes (priv
and pub
) which point to respective key material files.
We should allow for different configurations (e.g., a secret-name
from AWS Secrets Manager, or Hashicorp Vault) to be used to specify how to retrieve the key material.
In debug
mode OpaReactiveAuthorizationManager
logs the JWT that is sent to OPA
This is a serious security issue, and needs to be removed.
Currently JwtProvider
configures the expires_at
at a set time based on the expires_after_sec
configuration value.
We should add the ability to either not expiring the token, or to set an arbitrary expiration time (or duration)
We currently log the headers' contents; however the Authorization header has sensitive information that should not be logged (like we obfuscate the contents of the JWT)
The current version of testcontainers
(1.15.1
) has a transitive vulnerability:
Provides transitive vulnerable dependency org.apache.commons:commons-compress:1.20
There should be a boolean
configuration option (something like logging.audits.enabled
).
When enabled, each request should be logged with sufficient detail so that requests, users, and outcomes can be logged and stored for future audits.
At a minimum, we should log (in JSON format) the request body sent to OPA, the policy endpoint being queried, and the outcome (result) from the OPA server.
The JWT API token should be "unwrapped" to report (at a minimum) the user making the request, their roles
and the token expiration date.
We currently only send the path
and method
to OPA for authorization (alongside the JWT); we should also send "relevant" (as defined by the user) headers.
This could be a mix of "well-known" as well as "custom" headers:
opa:
headers:
- x-org-id
- x-user-def
- ContentType
If any (or all) of the headers are missing in the API call, they are simply ignored and the authorization is sent to OPA: auth policies will decide if those are required and access ought to be denied if missing.
The headers
will be sent in the OPA request as key-value pairs (we assume single-valued headers):
{
"input": {
"api_token": ".... API Token Base-64 encoded ...",
"resource": {
"method": "POST",
"path": "/path/to/resource",
"headers": [
{ "name": "x-org-id", "value": "123456"},
{ "name": "ContentType", "value": "application/json"},
...
]
}
}
}
and will be available as an array of objects in the Rego policy at input.resource.headers
, and each header will be accessible as, for example input.resource.headers["x-org-id"]
.
Currently the KeypairReader
is implemented by a file reader and an AWS (Secrets Manager) reader.
While the implementation is reasonably straightforward, the configuration of the client(s) (via a @Configuration
class) is "left to the implementer" - which is not a desirable state of affairs.
Also, there is some cruft left over from moving the key configuration out of the tokens configuration - so that needs cleaning up too.
The challenge is how to define both @Properties
and @Configuration
classes (and the associated structure of the YAML properties) without constraining too much what can be added later on (and also without making the Bean instantiation too cumbersome).
This task is partly designing the above, as well as a "reference implementation", including providing documentation and examples.
Gradle 7.4 has been released.
It makes it easier to create a single test report or JaCoCo code coverage report across several projects, makes it easier to gradually adopt configuration cache, promotes central declaration of dependencies to stable, and includes many other improvements.
See release notes for details.
Even at DEBUG level for com.alertavert
when the auth fails we don't get good logging to figure out what went wrong during development/testing.
We recently tested and the JWT was expired, but it was not clear at all that that was the issue.
Upgrading to the most recent Spring version, raises a number of deprecation warnings:
> Task :jwt-opa:compileJava
/home/marco/Development/jwt-opa/jwt-opa/src/main/java/com/alertavert/opa/configuration/JwtSecurityConfiguration.java:65: warning: [removal] csrf() in ServerHttpSecurity has been deprecated and marked for removal
.csrf().disable()
^
/home/marco/Development/jwt-opa/jwt-opa/src/main/java/com/alertavert/opa/configuration/JwtSecurityConfiguration.java:73: warning: [removal] httpBasic() in ServerHttpSecurity has been deprecated and marked for removal
.httpBasic()
^
/home/marco/Development/jwt-opa/jwt-opa/src/main/java/com/alertavert/opa/configuration/JwtSecurityConfiguration.java:74: warning: [removal] and() in ServerHttpSecurity.HttpBasicSpec has been deprecated and marked for removal
.and()
^
/home/marco/Development/jwt-opa/jwt-opa/src/main/java/com/alertavert/opa/configuration/JwtSecurityConfiguration.java:76: warning: [removal] authorizeExchange() in ServerHttpSecurity has been deprecated and marked for removal
.authorizeExchange()
^
/home/marco/Development/jwt-opa/jwt-opa/src/main/java/com/alertavert/opa/configuration/JwtSecurityConfiguration.java:81: warning: [removal] and() in ServerHttpSecurity.AuthorizeExchangeSpec has been deprecated and marked for removal
.and()
^
/home/marco/Development/jwt-opa/jwt-opa/src/main/java/com/alertavert/opa/security/OpaReactiveAuthorizationManager.java:160: warning: [removal] getMethodValue() in HttpRequest has been deprecated and marked for removal
request.getMethodValue(),
^
6 warnings
This must be fixed.
Using an UUID (e.g, an ObjectId
) that references an actual JWT (Token) stored in a service's DB (for example)
Similarly to UserDetails
we could define an interface TokenDetails
which, when implemented as a Bean
returns a JWT (if it exists) when requested by UUID.
This would allow use cases around rotating and revoking tokens.
This library currently assumes the keypair to be stored in the filesystem, while in reality, keys may be obtained instead from, e.g., secure vaults (such as Hashicorp Vault or AWS Secrets Manager).
We should allow for the ability for the users of the library to provide the keypair in ways other than filesystem storage.
We currently build the OPA request path following the static definition in the opa
property:
# This is used to build the Rule validation endpoint:
# http://localhost:8181/v1/data/com/alertavert/policies/allow
#
opa:
policy: com.alertavert.policies
rule: allow
server: "localhost:8181"
and this is used for all API calls, regardless of the request path (see the OpaReactiveAuthorizationManager
class).
It should be possible to define a "matching pattern" between URL path and OPA Rule to evaluate policies more flexibly; something like:
opa:
server: ...
policies:
- path_glob: "/users/**"
policy: com.alertavert.users
rule: allow
- path_glob: "/orders/*/status"
policy: com.alertavert.orders
rule: inspect
- path_glob: "*"
policy: com.alertavert.policies
rule: allow
Paths' globs are "ant patterns" similarly to what is being used in the routes
configuration (see the JwtSecurityConfiguration
class)
We currently only generate Tokens upon validating credentials (typically, username/password).
We should augment the functionality for this library users to generate "Refresh Tokens," which have a much longer validity (eg., weeks or even months) but cannot be used for API authorization, only to obtain new API Tokens.
This would be useful when enabling services/bot to access APIs via JWTs, but not wanting to have to acquire a new token every time on expires by submitting credentials.
Service A trying to access Service B would then try to authenticate with a Token, and in case it receives a 401 (or a 403) they could try and refresh their token, and try again the request (assuming they successfully authenticate and obtain a valid new token).
Open JDK 17 has now been out for several months, and it is a LTS release; we should adopt it fully and then make it the default supported JDK release.
At this point we believe that this library is mature enough to achieve v1 release status.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.