Hi everyone,
I have provided a first version, you can check it out here:
https://github.com/apache/ofbiz-framework/pull/1790
Good news first:
Before any changes, the structure of apis as independant endpoints was
mostly already present, if not leveraged for something like
authentication based on the targeted api.
More specific:
On the current trunk, <api> enforce a non-optional path attribute,
unique to that api. That in effect makes each <api> defined via rest.xml
discoverable under a unique segment
.../rest/<api-path-element>/<optional-other-path-segments/...
That attribute is used as a key when api definitions get stored in
MICRO_APIs. The only necessary change to allow grouping apis was thus,
to allow apis to define the same path on <api> level. I renamed the path
element to "apiGroupPath" and provided the rest.xsd definition with
additional description to make that relationship clear. I changed
MICRO_API and related code from handling single ModelApis to working
with lists (Map<String, ModelApi> to Map<String, List<ModelApi>>). I
also added additional checks, to prevent apis of the same group from
defining the same endpoints.
Note that until here, there is no functional change to how the rest-api
works, its only organization so far.
Next i restructured existing apis and introduced "api" as the default
api group for ofbiz-native apis. Currently in ofbiz framework we have
the restExampleApi.rest.xml (renamed to testApi.rest.xml, since it
provides only endpoints for testing), bom-management.rest.xml,
production-runs.rest.xml, mrp-planning.rest.xml and rountg-cost.rest.xml.
I moved the path element previous defined at <api> level one resource
element down and changed apiGroupPath to "api". That means if an
endpoints was previously available at:
/rest/bom-management/someService
It will now be available at
/rest/api/bom-management/someService
I implemented an authorization check based on the apiGroup. I added
apiGroupPath as a Path-Parameter to the auth endpoint
/rest/auth/token -> /rest/auth/{apiGroupPath}/token
Prior to issuing the token, the SecurityGroup configured for the
rest-api is retrieved. If the user tries getting a token for a api that
has no securityGroup configured via via rest.api .properties, it will
deny the token and return this information to the user. If credentials
are valid and a token issued, the apiGroupPath ist then added to the
claims of the token issued. Upon verification it now validates if this
parameter matched the api the user calls after it verified that the
token itself is genuine. Creating a refresh token retrieves the
apiGroupPath and adds it to the new token automatically.
Regarding SwaggerUI:
Apis in swagger will now be filtered based on their apiGroup.
previously:
any call to /docs/ forwarded to /docs/swagger-ui.html
Now a filter intercepts all calls to the swagger webapp and checks
wether an explicit apiGroupPath is provided,
Previously: /docs/apiGroupPath/swagger-ui.html
swagger-ui.html itself does a call to
rest/openapi.json
where the swaggerUI is constructed. This endpoint changed to
rest/{apiGroupPath}/openapi.json
to allow the passing of the group we want to filter for. If the user
does not provide an apiGroupPath, swagger-ui.html sets it to the default
"api" to display ofbiz standard endpoints. For backwards compatability,
calling /docs/ also gets forwarded with the default.
To sum up the valid ways to reach swagger-ui:
/docs/ (displays apis for group "api" - backward-compatability)
/docs/swagger-ui.html (displays apis for group "api" -
backward-compatability)
/docs/api/swagger-ui.html (displays apis for group "api" - default)
docs/<someApiGroup>/swagger-ui.html /displays apis for group <someApiGroup>)
(Note that endpoints exposed as a resource like
rest/auth/{apiGroupPath}/token are independant of this filter and always
included)
I did intentionally NOT gate the swaggerUi itself. While we could hook a
simple login filter via web.xml, since wagger-ui.html internally does a
call to /rest/{apiGroupPath}/openapi.json the only way to secure it
truly would be to hide the endpoint behind authorization, which means we
would need to create an auth token for visiting swaggerUI itself. That
does not seem reasonable to me at this point.
Happy the receive your feedback, but note that I will be gone a few
days, will respond once im back.
Best regards,
Lukas