build.security provides simple development and management for your organization's authorization policy. opa-java-spring-client is a Spring middleware intended for performing authorization requests against build.security PDP(Policy Decision Point)/OPA.
Before you start we recommend completing the onboarding tutorial.
Important note
To simplify the setup process, the following example uses a local build.security PDP instance. If you are already familiar with how to run your PDP, You can also run a PDP on you environment (Dev/Prod, etc).
In that case, don't forget to change the hostname and the port in your code.
Configure the PDP client component by setting the following properties in your application.properties:
pdp.enable=true
pdp.allowOnFailure=false
pdp.port=8181
pdp.hostname=localhost
pdp.policy.path=/authz/allow
pdp.readTimeout.milliseconds=5000
pdp.connectionTimeout.milliseconds=5000
pdp.retry.maxAttempts=2
pdp.retry.backoff.milliseconds=250
pdp.hostname
: The hostname of the Policy Decision Point (PDP)pdp.port
: The port at which the OPA service is runningpdp.policyPath.path
: Full path to the policy (including the rule) that decides whether requests should be authorized
How to get your pdp's hostname and port?
pdp.enable
: Boolean. Whether or not to enable interception of requests for authz. Default is truepdp.interceptAllEndpoints
: Boolean. Whether all endpoints should be intercepted, regardless of whether their associated controllers have a anAuthorize
annotation or not. Default is truepdp.ignoreEndpoints
: Array. Only set whenpdp.interceptAllEndpoints
is true: a list of endpoints that shouldn't be intercepted for authz.pdp.ignoreRegex
: Array. Only set whenpdp.interceptAllEndpoints
is true: a list of regex patterns that match endpoints that shouldn't be intercepted for authz.pdp.allowOnFailure
: Boolean. "Fail open" mechanism to allow access to the API in case the policy engine is not reachable. Default is false.pdp.readTimeout.milliseconds
- Integer. Read timeout for requests in milliseconds. Default is 5000pdp.connectionTimeout.milliseconds
- Integer. Connection timeout in milliseconds. Default is 5000pdp.retry.maxAttempts
- Integer. the maximum number of retry attempts in case a failure occurs. Default is 2.pdp.retry.backoff.milliseconds
- Integer. The number of milliseconds to wait between two consecutive retry attempts. Default is 250
Register your PDP as a spring interceptor
@Configuration
public class Configurer implements WebMvcConfigurer {
@Autowired
private PdpInterceptor pdpInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(pdpInterceptor);
}
}
Example implementation in a Spring Controller
// The Authorize annotation indicates that this request should be be authorized
// using the PDP request interceptor. The resources supplied in the annotation will be
// sent on the PDP request as well.
@Authorize(resources = {"sdk.view"})
@RequestMapping("/sdk")
public String sdkExample(HttpServletRequest request) throws Exception {
// ... Controller logic
}
Or instead use PDPClient directly to issue a request with your own input
@RequestMapping("/sdk")
public String sdkExample(HttpServletRequest request) throws Exception {
Map<String, String> headers = new HashMap<String, String>();
for (Enumeration<String> headerNames = request.getHeaderNames(); headerNames.hasMoreElements(); ) {
String header = headerNames.nextElement();
headers.put(header, request.getHeader(header));
}
String[] path = request.getRequestURI().replaceAll("^/|/$", "").split("/");
//define the input for evaluation
//In your application, you can put anything you'd like on the input for policy evaluation
Map<String, Object> input = new HashMap<String, Object>();
input.put("group", "group1");
input.put("environment", "staging");
input.put("role", "admin");
JsonNode node = null;
try {
node = pdpClient.getJsonResponse(input);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return node.toPrettyString();
}
Run your PDP (OPA) instance (assuming it runs on localhost:8181) and your spring server(localhost:8080).
- Please make sure to define some pdp policy rules.
This is what the input received by the PDP would look like.
{
"input":{
"request":{
"scheme":"http",
"method":"GET",
"path":"websecurity",
"query":{
},
"headers":{
"host":"localhost:8080",
"user-agent":"curl/7.64.1",
"accept":"*/*"
}
},
"resources":{
"requirements":[
"websecurity"
],
"attributes":{
}
},
"source":{
"ipAddress":"172.19.0.1",
"port":0
},
"destination":{
"ipAddress":"172.19.0.2",
"port":0
}
}
}
If everything works well you should receive the following response:
{
"decision_id":"ef414180-05bd-4817-9634-7d1537d5a657",
"result":true
}