The FIWARE PEP Proxy – Wilma is a key component of the IoT stack of the FIWARE ecosystem. The proxy is used for securing REST APIs, effectively introducing authentication and authorization as an aspect to existing HTTP-based services.
Architecture
The PEP Proxy is a compact NodeJS service. It intercepts incoming HTTP/HTTPS calls, checking the validity of the included OAuth2 token and verifies whether the associated principal can perform the action (HTTP method) to the resource (HTTP URL) specified in the call. In short, it operates as an identity service for OAuth2 bearer-only endpoints and adds HTTP-based authorization verification.
The PEP Proxy makes certain assumptions regarding its deployment environment:
- The availability of the FIWARE Keyrock IDM and an existing service account bound to the PEP Proxy.
- In case the PEP Proxy performs authorization checks on the incoming calls, an instance of the AuthZForce service is used for storing and verifying access policies.
- The PEP proxy authenticates itself to the IDM using its service credentials (attributes config.username & config.password found in config.js). The proxy username & password must be registered with the IDM. In addition an application corresponding to the proxy must be created in the IDM.
- The PEP proxy intercepts the incoming service call. This involves 2 steps:
- The OAuth2 token in the incoming call is verified with the IDM.
- The user’s roles, the action, the resource and the application ID are forwarded to the Authorization PDP server that compares the request with the set of access policies stored in the server.
Interactions
PEP Proxy Authentication
The PEP proxy needs to retrieve an access token from the IDM in order to be able to validate incoming OAuth2 tokens on behalf of clients and retrieve details regarding the associated user roles.
The PEP proxy username and password is retrieved from the top-level config.js file.
POST /v3/auth/tokens HTTP/1.1 User-Agent: node-XMLHttpRequest Accept: */* Content-Type: application/json Host: idm:5000 Content-Length: 175 Connection: close { "auth": { "identity": { "methods": [ "password" ], "password": { "user": { "name": "pepproxy@test.com", "password": "test", "domain": { "id": "default" } } } }, "scope": { "domain": { "id": "default" } } } }
The access token is included in the reply in the X-Subject-Token header.
HTTP/1.1 201 Created X-Subject-Token: 91ca078990524002ba7777fa0bf4408b Vary: X-Auth-Token Content-Type: application/json Content-Length: 959 Date: Mon, 07 Mar 2016 21:02:37 GMT Connection: close { "token": { "domain": { "id": "default", "name": "Default" }, "methods": [ "password" ], "roles": [ { "id": "be19ae44014349c4a9dd614bb413ab64", "name": "member" } ], "expires_at": "2016-03-07T22:02:37.646619Z", "catalog": [ { "endpoints": [ { "region_id": "Spain2", "url": "http://127.0.0.1:35357/v3/", "region": "Spain2", "interface": "internal", "id": "39aec7cd210f439c974b0dce52983d50" }, { "region_id": "Spain2", "url": "http://127.0.0.1:35357/v3/", "region": "Spain2", "interface": "admin", "id": "78db8f42965e43c8b54ae587ef067d9a" }, { "region_id": "Spain2", "url": "http://127.0.0.1:5000/v3/", "region": "Spain2", "interface": "public", "id": "835b7fd1e3f34f9aa88db817b7ab5f03" } ], "type": "identity", "id": "6ffd78687e984bfe8da5eb8f812296ca", "name": "keystone" } ], "extras": {}, "user": { "domain": { "id": "default", "name": "Default" }, "id": "pepproxy", "name": "pepproxy@test.com" }, "audit_ids": [ "_jj9BFuoRSC2CrKcpib0Jg" ], "issued_at": "2016-03-07T21:02:37.646646Z" } }
Client Authentication
Client requests to the protected service are intercepted by the PEP proxy. The proxy validates the associated OAuth2 token with the IDM. The token is pulled from the X-Auth-Token header or the standard OAuth2 Authorization: Bearer {token} header.
The client retrieves an OAuth2 token directly from the IDM service using the confidential direct-grant flow:
POST /oauth2/token HTTP/1.1 User-Agent: curl/7.38.0 Host: idm Accept: */* Authorization: Basic MDczNzUzZmNmNDBmNDVmNzhhMDIwZDYxNDBiNzY5YjQ6NzMzNDc3N2I1MDgzNDk0MGEzZmM3OTA5Yjc2Y2EyYTQ= Content-Type: application/x-www-form-urlencoded Content-Length: 147 grant_type=password&username=user0@test.com&password=test&client_id=073753fcf40f45f78a020d6140b769b4&client_secret=7334777b50834940a3fc7909b76ca2a4
HTTP/1.1 200 OK Date: Mon, 07 Mar 2016 21:45:20 GMT Server: Apache/2.4.7 (Ubuntu) Vary: Accept-Language,Cookie X-Frame-Options: SAMEORIGIN Content-Language: en Transfer-Encoding: chunked Content-Type: application/json { "access_token": "XCTiZUacuABA37VtxlRmIVDufHkbdJ", "token_type": "Bearer", "expires_in": 3600, "refresh_token": "0CO2ZnmvTqJ77Wj1IrtlzGMeIQ7cPg" }
Then the client issues a call to the protected service. In this case, the client issues a request to the Orion context broker to create a context with 2 attributes.
POST /v1/updateContext HTTP/1.1 Host: 192.168.99.100:1026 Connection: keep-alive Content-Length: 517 Accept: application/json Cache-Control: no-cache x-auth-token: tQUD24RjIdrKNhG6YBzEzQnrfUMR3x Content-Type: application/json User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.75 Safari/537.36 Origin: chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop Postman-Token: 875cff8c-4a89-9098-d716-138088e0025e Accept-Encoding: gzip, deflate Accept-Language: en-US,en;q=0.8 { "contextElements": [ { "type": "Room", "isPattern": "false", "id": "Room1", "attributes": [ { "name": "temperature", "type": "float", "value": "23" }, { "name": "pressure", "type": "integer", "value": "720" } ] } ], "updateAction": "APPEND" }
The PEP proxy validates the incoming token. The URL contains the client token to be validated. The X-Auth-Token header holds the PEP proxy access token.
GET /v3/access-tokens/tQUD24RjIdrKNhG6YBzEzQnrfUMR3x HTTP/1.1 User-Agent: node-XMLHttpRequest Accept: application/json X-Auth-Token: 91ca078990524002ba7777fa0bf4408b Host: idm:5000 Connection: close
In addition to validating the token, the reply includes the user’s roles and the ID of the application that the token has been issued for.
HTTP/1.1 200 OK Vary: X-Auth-Token Content-Type: application/json Content-Length: 216 Date: Mon, 07 Mar 2016 21:34:38 GMT Connection: close { "organizations": [], "displayName": "user0", "roles": [ { "name": "Orion Operations", "id": "a7cdfe346dd2468085e09c235d2a8311" } ], "app_id": "073753fcf40f45f78a020d6140b769b4", "email": "user0@test.com", "id": "user0" }
Client Authorization
The PEP proxy generates an authorization request to AuthZForce using the user’s details retrieved during the token validation and the initial client request that contains the resource and the action.
The resource ID refers to the PEP proxy application ID registered with the IDM. The request path /authzforce/domains/032543f7-da0a-11e5-b595-15ad990bc8c9 is retrieved from the config.js file. The included domain ID refers to the registered domain in AuthZForce.
POST /authzforce/domains/032543f7-da0a-11e5-b595-15ad990bc8c9/pdp HTTP/1.1 User-Agent: node-XMLHttpRequest Accept: application/xml X-Auth-Token: tQUD24RjIdrKNhG6YBzEzQnrfUMR3x Content-Type: application/xml Host: authzforce:8080 Content-Length: 1406 Connection: close <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Request xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" CombinedDecision="false" ReturnPolicyIdList="false"> <Attributes Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"> <Attribute AttributeId="urn:oasis:names:tc:xacml:2.0:subject:role" IncludeInResult="false"> <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">a7cdfe346dd2468085e09c235d2a8311</AttributeValue> </Attribute> </Attributes> <Attributes Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"> <Attribute AttributeId="urn:oasis:names:tc:xacml:1.0:resource:resource-id" IncludeInResult="false"> <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">073753fcf40f45f78a020d6140b769b4</AttributeValue> </Attribute> <Attribute AttributeId="urn:thales:xacml:2.0:resource:sub-resource-id" IncludeInResult="false"> <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">v1/updateContext</AttributeValue> </Attribute> </Attributes> <Attributes Category="urn:oasis:names:tc:xacml:3.0:attribute-category:action"> <Attribute AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id" IncludeInResult="false"> <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">POST</AttributeValue> </Attribute> </Attributes> <Attributes Category="urn:oasis:names:tc:xacml:3.0:attribute-category:environment"></Attributes> </Request>
HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Date: Mon, 07 Mar 2016 21:34:38 GMT Content-Type: application/xml Content-Length: 316 Connection: close <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Response xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" xmlns:ns2="http://thalesgroup.com/authzforce/pdp/model/2014/12"> <Result> <Decision>Permit</Decision> <Status><StatusCode Value="urn:oasis:names:tc:xacml:1.0:status:ok"/></Status> </Result> </Response>
References
- Bitergia’s sample Orion/Wilma/IDM/AuthZForce application fully based on Docker.
https://github.com/Bitergia/fiware-chanchan-docker - PEP proxy source.
https://github.com/ging/fiware-pep-proxy