OpenAPI restrict path to 'admin' users - openapi

In OpenAPI, how to you restrict a given action (e.g. GET /users) to users with a specific role (e.g. admin)?
Example, where the list of users should only be accessible to admin users:
paths:
/users:
get:
# TODO: restrict access to users with 'admin' role
summary: Get list of all users
security:
- BearerAuth: []
operationId: getUsers
responses:
200:
description: successful operation
content:
application/json:
schema:
type: object
properties:
users:
type: array
items:
$ref: '#/components/schemas/User'

Bearer Authorization does not support access scopes as defined with OpenAPI. You have a few options:
Use A Description
Use a description to explain to readers of your definition that these endpoints require an auth token belonging to an admin user. This is the simplest solution, though this won't allow tooling to automatically enforce this criteria from your OpenAPI spec, so you'll need to manually control this in your own code.
get:
description: Get list of all users. Limited to admin users.
Use An Extension
Write an extension to formally describe the criteria necessary for your auth tokens. OpenAPI allows the use of extra properties for defining properties and behaviors that are specific to your implementation that don't fit the generic case. You can write tooling and scripts to process this property to enforce behavior as you see fit.
get:
x-authRoles: ['admin']
Use OAuth 2.0
Use OAuth 2.0 or another security scheme that supports access scopes by design. You may find this adds additional security benefits, as all tooling around OAuth already expects access scopes, so you may have an easier time with this particular problem, as you won't have to roll your own implementation.
get:
security:
- oAuthSample:
- admin

Related

Is group name case sensitive in SAML payload (in Palantir Foundry context)?

During a SAML login via multipass, a list of groups is provided in the payload in <saml:Attribute Name="https://schemas.xmlsoap.org/claims/Group" ...>
Are these groups matched case-sensitively?
i.e.: Will a group that was provided as "AbcDef" earlier, but is provided as "abcdef" later be treated as the same group or not?
You can now modify your SAML configuration in a self-serve way via Foundry Control Panel.
For user attributes: please reach out through your internal support channel if you'd like to make user attributes case-sensitive - this option isn't available in the UI.
For user groups: case sensitivity isn't currently supported for user groups. You need to enable the “Import user groups from the identity provider” option to populate a user's groups via SAML.
This is a multipass configuration service level configuration. You will need access to the gemini or the infrastructure that configures the stack itself to change it. If you don't please reach out through your internal support channels.
What you want is to add caseInsensitive to the type in your atributes. i.e.:
users:
attributes:
'multipass:email:primary':
- Email
'multipass:family-name':
- 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname'
'multipass:given-name':
- 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname'
id:
fields:
- NameID
type: caseInsensitive
username:
- NameID

How to search keycloak users by employeeNumber or by custom attributes?

I wanted to search keycloak user using employeeNumber. I tried checking keycloak documentation but didn't find any API which will search based on employeeNumber/custom attributes. I m using below API to search the users with admin access.
http://localhost:8080/auth/admin/realms/Demo-Realm/users/?firstName=akshay
also tried with
http://localhost:8080/auth/admin/realms/Demo-Realm/users/?search=akshay
Although not mentioned on the release notes it is possible after Keycloak version 15.1.0 (as pointed out by #Darko) to search users by custom attributes, introduced with this commit. As one can now see on the GET /{realm}/users endpoint of the Keycloak Admin Rest API:
So in your case you would call that endpoint with the query parameter q=employeeNumber, for instances with curl:
curl 'https://${KEYCLOAL_HOST}/auth/admin/realms/${REALM_NAME}/users?q=employeeNumber:444555'
Bear in mind that the /auth path was removed starting with Keycloak 17 Quarkus distribution. So you might need to remove the /auth, namely:
curl 'https://${KEYCLOAL_HOST}/admin/realms/${REALM_NAME}/users?q=employeeNumber:444555'
Keycloak version before 15.1.0
For those with Keycloak version before 15.1.0, out-of-the-box you can use the Keycloak Admin API endpoint:
GET /{realm}/users
one can read that :
Get users Returns a list of users, filtered according to query
parameters
those (optional) query parameters being:
briefRepresentation (boolean);
email (string);
first (string);
firstName (string);
lastName (string);
max (Maximum results size (defaults to 100)) (integer);
search (A String contained in username, first or last name, or email);
username (string).
As you can see you cannot search for custom attributes. A not so great solution is to get all the users (max=-1), and filter afterwards by the custom attribute.
The other option is to extend Keycloak functionality by adding your own custom Service Provider Interfaces (SPI) and adding your custom endpoint. There you can take advantage of the searchForUserByUserAttribute method from the UserQueryProvider interface.

Openapi spec design for network equipment

I'm working on some API service which consume REST queries (CRUD operations) and send appropriate CLI commands to some network equipment.
There is 2 possible ways to design Openapi specification for this service:
Detailed huge API spec. Describe exactly all the endpoints, all the schemas, all the params that exist in the network equipment CLI. I think specification will be about 100K of lines in this way. Specification can be autogenerated based on device CLI parsing (using ? and TAB keys).
Generalized tiny API spec. Hide all device configuration details in a few common parameters. Something like
paths:
/api/{CLI_endpoint}: # we say "CLI_endpoint" instead of describing all the endpoints
...
post:
requestBody:
content:
application/json:
schema:
type: object # we say "object" instead of describing all the params
In this way we simply say that all the endpoint names and param names correspond to network equipment CLI documentation.
Which of the ways will be better?

Is endpoint unit testing possible based on only OpenAPI 3.0 file?

After some googling I decided to directly ask this:
Is it possible to run REST API endpoint "build tests" based on solely an OpenAPI 3.0 specification file?
I would like to add example request-response pairs to the OpenAPI spec file and have either an existing or self-written library run through all the such defined tests and report any failures.
As far as I understand the standard, it would be easily possible to include examples for requests and test the response in a schematic way (thinking http://json-schema.org/). But I don't yet see a way to incorporate more specific tests, such as testing a number in a specific response field to be an exact value. Also, it would be nice to have a way to sequentially test requests, but I don't expect to achieve that just from the spec file.
An optimal solution would be included in my repository and run the tests on localhost. Thank you all very much in advance.
Is it possible to run REST API endpoint "build tests" based on solely an OpenAPI 3.0 specification file?
Yes. The spec has at least two components that allow automatic tests generation:
Examples. You could specify examples for defined endpoints, which describe concrete data samples you send/receive.
Schemas. They describe data models, which you can use to generate requests to the API.
But I don't yet see a way to incorporate more specific tests, such as testing a number in a specific response field to be an exact value.
It can be done using the "enum" keyword with a single value in a list in the schema for the desired field. Open API doesn't support the "const" keyword in contrast with JSON Schema.
Also, it would be nice to have a way to sequentially test requests, but I don't expect to achieve that just from the spec file.
To achieve that you could use Open API links, which allows you to specify how to construct a request to endpoint B from request or response to endpoint A. For example:
paths:
/users:
post:
summary: Creates a user and returns the user ID
operationId: createUser
responses:
'201':
description: Created
content:
application/json:
schema:
type: object
properties:
id:
type: integer
format: int64
description: ID of the created user.
links:
GetUserByUserId:
operationId: getUser
parameters:
userId: '$response.body#/id'
/users/{userId}:
get:
summary: Gets a user by ID
operationId: getUser
parameters:
- in: path
name: userId
required: true
schema:
type: integer
format: int64
In this example, the id value returned in the 201 response to the POST /users can be used as the userId parameter in GET /users/{userId}. In this way, you can define sequences of requests to different endpoints.
I want to note two tools that can generate and execute test cases based only on the input Open API spec:
Schemathesis uses both sources and doesn't require configuration by default. It utilizes property-based testing and verifies properties defined in the tested schema - response codes, schemas, and headers. It supports Open API 2 & 3 and stateful testing via Open API links and automatically can generate sequences of API requests based on their definition in the spec file.
Dredd focuses more on examples and provides several automatic expectations. It supports only Open API 2, and the third version is experimental.
Both provide a CLI and could be extended with various hooks to fit the desired workflow.

Meteor: REST collection API and auth

In the need to expose part of my Meteor collections through REST, I stumbled across a the Collection API Meteorite package.
Whereas this indeed makes it possible to expose a Meteor Collection through REST, it does not take any security into account. Is there any way I can integrate the Collection API with the Meteor auth system introduced in 0.5.2?
Yes, kinda. Using the REST meteorite package, you can declare your collection and then use the allow rules on the collection, but with a couple caveats (NOTE: this is pseudo-code that requires more work!):
Players = new Meteor.Collection("players");
//a collection of associated userids and auth token headers
APIUsers = new Meteor.Collection("apiusers");
Players.allow({
insert: function (userId, doc) {
//invoking this from a RESTful context means the userId is NOT
//available, so you'll need to do three things things:
// (1) a way to get the current http request's X-Auth-Token header
// (2) a collection to look up the user(s) associated with
// that token
// (3) and an owner field on the Players collection to join back
// to the found userids.
return (_.indexOf(APIUsers.findOne(
{XAuthToken: __CURRENT_X_AUTH_TOKEN__}).users
, doc.owner) > -1;
},
update: function (userId, docs, fields, modifier) {
/* similar logic */
},
remove: function (userId, docs) {
/* similar logic */
},
fetch: ['owner']
});
BUT while I think the RESTful approach will prove useful in integrating legacy applications into a Meteor context, I would highly recommend looking into the DDP protocol for integration of new projects.
As you can see above, the allow rules do not expose a GET callback, presumably because the expectation is the GET is defined in the publication the server exposes. A DDP client is wired at a lower level to subscribe to these publications, so GETs in this context will be much more granular than a RESTful approach.
For anyone stumbling across this now, Restivus allows you to generate REST endpoints on collections, and configure user authentication and role permissions on those endpoints. The default authentication uses Meteor's built-in login token mechanism to authenticate a Meteor.user and provide access to this.user and this.userId in authenticated endpoints. You can also provide a custom authentication method if the default is too much, or not enough, for you. Here's a quick example (hope you can read CoffeeScript):
# Generates: GET, POST on /api/users and GET, DELETE on /api/users/:id for
# Meteor.users collection
Restivus.addCollection Meteor.users
excludedEndpoints: ['deleteAll', 'put']
routeOptions:
authRequired: true
endpoints:
post:
authRequired: false
delete:
roleRequired: 'admin'