Copyright © 2005-2025
Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically.
Overview
This guide describes the RESTful API of the OpenWMS.org UAA (User Authentication & Administration) module and its usage. Some general terms and definitions are explained and declared in the first part of the document whereas in the second part the usage of the API is shown in a more use-case-driven approach.
Resources
A description of all used API resources.
Representation Formats
Basically JSON is used as representation format by default if not otherwise requested or mentioned below. XML format is supported for the
index pages as well, but must be requested explicitly. Furthermore a vendor specific JSON format is used to represent resource
representations. Therefore it’s absolutely required the Accept
header denotes the demanded type. Find the type in the examples below.
Dates in JSON
Date or datetime fields are not treated specially in JSON. Within the scope of this API a date or datetime field is always expected and
rendered as JSON String in ISO8601 format with timezone information and milliseconds: yyyy-MM-dd’T’HH:mm:ssXXX
.
Embedded Entities
For the sake of convenience some response entities may included embedded entities or even parts of it. A reference to the actual entity is provided as HAL link as well.
Error Responses
Beside the actual representation of resources, the server may result an error response in JSON format that contains basic information about the error occurred. This information is additional to the standard HTTP status code and may help clients to identify the error cause in order to re-phrase and send the request again.
Currently there are two types of errors with their own response formats.
Server Declined Errors
This kind of errors are sent by the server runtime environment even before the request had a chance to be processed.
An example response looks like this:
{
"timestamp": 1512400854941,
"status": 500,
"error": "Internal Server Error",
"exception": "org.ameba.oauth2.InvalidTokenException",
"message": "JWT expired at 2017-12-04T15:04:43Z. Current time: 2017-12-04T15:20:54Z, ...",
"path": "/v1/transport-units?bk=00000000000000004711"
}
The JSON structure contains the following fields.
Property Name | Description |
---|---|
timestamp |
When the error occurred on server side |
status |
The http status of the error |
error |
A short error text |
exception |
Internal class name of the Java exception type |
message |
A more descriptive error text describing the error in detail |
path |
The part of the URI for the REST resource that was queried |
API Declined Errors
Those errors are thrown within the REST API validation and processing logic. For example, if a client request does not match the expected format or has produced an error on server side, the API will decline the request and return a response with status client-side error (4xx).
The structure of the response is aligned to the RFC7808. An example response looks like this:
{
"message": "LocationGroup with name [NOT_EXISTS] not found",
"messageKey": "owms.common.common.lg.notFoundByName",
"obj" : [ "NOT_EXISTS" ],
"httpStatus" : "404",
"class" : "String"
}
The JSON structure contains the following fields.
Property Name | Description |
---|---|
message |
A short error text |
messageKey |
An unique identifier across the API that can be used to identify and translate the error message on the client side |
obj |
An array of possible passed arguments to the message |
httpStatus |
The http status of the error |
class |
The arguments type |
Following message keys are currently used:
Message Key | Description | Action |
---|---|---|
not.found |
The requested resource has not been found |
The resource does not exist anymore or has never existed. The resource identifier must be verified |
Index
The initial HTTP request to retrieve information about all available resources looks like the following. The Index page is a public available resource and does not need any authentication.
GET /index HTTP/1.1
Host: localhost:8080
The Index
resource is returned in the response body with the response status of 200-OK. This main Index
lists all primary resource
entities to follow next.
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 260
{
"_links" : {
"user-index" : {
"href" : "http://localhost:8080/users/index"
},
"role-index" : {
"href" : "http://localhost:8080/roles/index"
},
"grant-index" : {
"href" : "http://localhost:8080/grants/index"
}
}
}
A client application only needs to know about the agreed link names and follow the corresponding href
link to navigate to further
resources.
User
A User
represents a human user of the system, usually in front of an UI who interacts with the system. User
representations can be
created, modified and retrieved. An User
is also allowed to authenticate against an UAA endpoint.
User Index
An overview of all possible operations on Users
can be found on the User
index page that is retrieved with a GET
request:
GET /users/index HTTP/1.1
Host: localhost:8080
And the server responds with a HAL+JSON
representation to further operations:
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 725
{
"_links" : {
"users-findbypkey" : {
"href" : "http://localhost:8080/users/%7BpKey%7D"
},
"users-findall" : {
"href" : "http://localhost:8080/users"
},
"users-findgrants" : {
"href" : "http://localhost:8080/users/%7BpKey%7D/grants"
},
"users-create" : {
"href" : "http://localhost:8080/users"
},
"users-save" : {
"href" : "http://localhost:8080/users"
},
"users-saveimage" : {
"href" : "http://localhost:8080/users/%7BpKey%7D/details/image"
},
"users-change-password" : {
"href" : "http://localhost:8080/users/%7BpKey%7D/password"
},
"users-delete" : {
"href" : "http://localhost:8080/users/%7BpKey%7D"
}
}
}
Create an User
To create a new User
instance, a POST
request must be send to the server with the mandatory fields of the User
resource in the request
body.
POST /users HTTP/1.1
Content-Type: application/json
Content-Length: 140
Host: localhost:8080
{
"links" : [ ],
"username" : "admin2",
"emailAddresses" : [ {
"emailAddress" : "admin2@example.com",
"primary" : true
} ]
}
Path | Type | Description |
---|---|---|
|
|
The unique name of the User in the system |
|
|
The User’s email addresses |
|
|
The actual email address |
|
|
Whether this email address is the primary one used in the system. Each User can only have one primary email address |
If the User
has been created successfully, the server returns the URI to the created resource in the Location
header:
HTTP/1.1 201 Created
Location: http://localhost:8080/users/46033140-6938-4aca-b7e4-46079e7a36f6
Content-Type: application/vnd.openwms.uaa.user-v1+json
Content-Length: 377
{
"ol" : 0,
"createDt" : "2025-02-04T23:09:57.614447136Z",
"lastModifiedDt" : "2025-02-04T23:09:57.614447136Z",
"pKey" : "46033140-6938-4aca-b7e4-46079e7a36f6",
"username" : "admin2",
"externalUser" : false,
"locked" : false,
"enabled" : true,
"emailAddresses" : [ {
"emailAddress" : "admin2@example.com",
"primary" : true
} ],
"roleNames" : [ ]
}
If an User
with the same name already exists the server returns an error:
HTTP/1.1 409 Conflict
Content-Type: application/hal+json
Content-Length: 166
{
"message" : "User with name tester already exists",
"messageKey" : "user.already.exists",
"obj" : [ "tester" ],
"httpStatus" : "409",
"class" : "String"
}
Find all Users
To find and retrieve an array of all existing Users
a client may call a GET
request:
GET /users HTTP/1.1
Host: localhost:8080
and returns either an array of Users
…
HTTP/1.1 200 OK
Content-Type: application/vnd.openwms.uaa.user-v1+json
Content-Length: 1662
[ {
"links" : [ {
"rel" : "user-findbypkey",
"href" : "http://localhost:8080/users/96baa849-dd19-4b19-8c5e-895d3b7f405d"
} ],
"ol" : 1,
"createDt" : "2020-06-22T19:02:47.404000000Z",
"lastModifiedDt" : "2025-02-04T23:10:00.068423000Z",
"pKey" : "96baa849-dd19-4b19-8c5e-895d3b7f405d",
"username" : "jenkins",
"externalUser" : true,
"lastPasswordChange" : "2020-06-22T19:02:47Z",
"locked" : true,
"enabled" : true,
"expirationDate" : "2020-06-23T19:02:45Z",
"fullname" : "Mister Jenkins",
"details" : { },
"emailAddresses" : [ {
"emailAddress" : "admin.private@acme.com",
"primary" : true,
"fullname" : "Mr. Jenkins"
}, {
"emailAddress" : "admin@acme.com",
"primary" : false,
"fullname" : "Mr. Jenkins"
} ],
"roleNames" : [ "ROLE_ADMIN" ],
"password" : "{bcrypt}$2a$15$baURCfRsoxem.eOv0IJDsup.9wEmHdiw.j8f0RaMflDbFnQWNipvG"
}, {
"links" : [ {
"rel" : "user-findbypkey",
"href" : "http://localhost:8080/users/96baa849-dd19-4b19-8c5e-895d3b7f405e"
} ],
"ol" : 1,
"createDt" : "2020-06-22T19:02:47.404000000Z",
"lastModifiedDt" : "2025-02-04T23:10:00.068423000Z",
"pKey" : "96baa849-dd19-4b19-8c5e-895d3b7f405e",
"username" : "tester",
"externalUser" : false,
"lastPasswordChange" : "2020-06-22T19:02:47Z",
"locked" : false,
"enabled" : true,
"expirationDate" : "2020-06-23T19:02:45Z",
"fullname" : "Tester",
"details" : { },
"emailAddresses" : [ {
"emailAddress" : "tester@acme.com",
"primary" : true,
"fullname" : "Mr. Tester"
} ],
"roleNames" : [ ],
"password" : "{bcrypt}$2a$15$baURCfRsoxem.eOv0IJDsup.9wEmHdiw.j8f0RaMflDbFnQWNipvG"
} ]
or an empty array, but always with a 200-OK
.
HTTP/1.1 200 OK
Content-Type: application/vnd.openwms.uaa.user-v1+json
Content-Length: 1649
[ {
"links" : [ {
"rel" : "user-findbypkey",
"href" : "http://localhost:8080/users/96baa849-dd19-4b19-8c5e-895d3b7f405d"
} ],
"ol" : 1,
"createDt" : "2020-06-22T19:02:47.404000000Z",
"lastModifiedDt" : "2025-02-04T23:09:50.079814000Z",
"pKey" : "96baa849-dd19-4b19-8c5e-895d3b7f405d",
"username" : "jenkins",
"externalUser" : true,
"lastPasswordChange" : "2020-06-22T19:02:47Z",
"locked" : true,
"enabled" : true,
"expirationDate" : "2020-06-23T19:02:45Z",
"fullname" : "Mister Jenkins",
"details" : { },
"emailAddresses" : [ {
"emailAddress" : "admin.private@acme.com",
"primary" : true,
"fullname" : "Mr. Jenkins"
}, {
"emailAddress" : "admin@acme.com",
"primary" : false,
"fullname" : "Mr. Jenkins"
} ],
"roleNames" : [ ],
"password" : "{bcrypt}$2a$15$baURCfRsoxem.eOv0IJDsup.9wEmHdiw.j8f0RaMflDbFnQWNipvG"
}, {
"links" : [ {
"rel" : "user-findbypkey",
"href" : "http://localhost:8080/users/96baa849-dd19-4b19-8c5e-895d3b7f405e"
} ],
"ol" : 1,
"createDt" : "2020-06-22T19:02:47.404000000Z",
"lastModifiedDt" : "2025-02-04T23:09:50.079814000Z",
"pKey" : "96baa849-dd19-4b19-8c5e-895d3b7f405e",
"username" : "tester",
"externalUser" : false,
"lastPasswordChange" : "2020-06-22T19:02:47Z",
"locked" : false,
"enabled" : true,
"expirationDate" : "2020-06-23T19:02:45Z",
"fullname" : "Tester",
"details" : { },
"emailAddresses" : [ {
"emailAddress" : "tester@acme.com",
"primary" : true,
"fullname" : "Mr. Tester"
} ],
"roleNames" : [ ],
"password" : "{bcrypt}$2a$15$baURCfRsoxem.eOv0IJDsup.9wEmHdiw.j8f0RaMflDbFnQWNipvG"
} ]
Find an User by persistent key
A newly created User
can be retrieved by following the URI in the Location
header of the response. This URI points to the created
resource:
GET /users/96baa849-dd19-4b19-8c5e-895d3b7f405d HTTP/1.1
Host: localhost:8080
If the resource exists the server responds with a 200-OK
and the User
representation in the response body.
HTTP/1.1 200 OK
Content-Type: application/vnd.openwms.uaa.user-v1+json
Content-Length: 892
{
"_links" : {
"user-findbypkey" : {
"href" : "http://localhost:8080/users/96baa849-dd19-4b19-8c5e-895d3b7f405d"
}
},
"ol" : 1,
"createDt" : "2020-06-22T19:02:47.404000000Z",
"lastModifiedDt" : "2025-02-04T23:09:57.674158000Z",
"pKey" : "96baa849-dd19-4b19-8c5e-895d3b7f405d",
"username" : "jenkins",
"externalUser" : true,
"lastPasswordChange" : "2020-06-22T19:02:47Z",
"locked" : true,
"enabled" : true,
"expirationDate" : "2020-06-23T19:02:45Z",
"fullname" : "Mister Jenkins",
"details" : { },
"emailAddresses" : [ {
"emailAddress" : "admin.private@acme.com",
"primary" : true,
"fullname" : "Mr. Jenkins"
}, {
"emailAddress" : "admin@acme.com",
"primary" : false,
"fullname" : "Mr. Jenkins"
} ],
"roleNames" : [ "ROLE_ADMIN" ],
"password" : "{bcrypt}$2a$15$baURCfRsoxem.eOv0IJDsup.9wEmHdiw.j8f0RaMflDbFnQWNipvG"
}
Find all Roles that are assigned to a User
A client might ask for all Roles
that are assigned to a User
resource. Therefore the client needs to query all roles
of the primary
User
:
GET /users/96baa849-dd19-4b19-8c5e-895d3b7f405d/roles HTTP/1.1
Host: localhost:8080
and get an array of Roles
back, that could also be empty:
HTTP/1.1 200 OK
Content-Type: application/vnd.openwms.uaa.role-v1+json
Content-Length: 2192
[ {
"@class" : "org.openwms.core.uaa.api.RoleVO",
"ol" : 1,
"pKey" : "1",
"name" : "ROLE_ADMIN",
"description" : "Super user role",
"immutable" : true,
"users" : [ {
"links" : [ ],
"ol" : 1,
"createDt" : "2020-06-22T19:02:47.404000000Z",
"lastModifiedDt" : "2025-02-04T23:10:00.152946000Z",
"pKey" : "96baa849-dd19-4b19-8c5e-895d3b7f405d",
"username" : "jenkins",
"externalUser" : true,
"lastPasswordChange" : "2020-06-22T19:02:47Z",
"locked" : true,
"enabled" : true,
"expirationDate" : "2020-06-23T19:02:45Z",
"fullname" : "Mister Jenkins",
"details" : { },
"emailAddresses" : [ {
"emailAddress" : "admin.private@acme.com",
"primary" : true,
"fullname" : "Mr. Jenkins"
}, {
"emailAddress" : "admin@acme.com",
"primary" : false,
"fullname" : "Mr. Jenkins"
} ],
"roleNames" : [ "ROLE_ADMIN" ],
"password" : "{bcrypt}$2a$15$baURCfRsoxem.eOv0IJDsup.9wEmHdiw.j8f0RaMflDbFnQWNipvG"
} ],
"grants" : [ {
"@class" : "org.openwms.core.uaa.api.SecurityObjectVO",
"ol" : 1,
"createDt" : "2025-02-04T23:10:00.152946000Z",
"lastModifiedDt" : "2025-02-04T23:10:00.152946000Z",
"pKey" : "5",
"name" : "SEC_UAA_USER_MODIFY",
"description" : "Permission to modify Users"
}, {
"@class" : "org.openwms.core.uaa.api.SecurityObjectVO",
"ol" : 1,
"createDt" : "2025-02-04T23:10:00.152946000Z",
"lastModifiedDt" : "2025-02-04T23:10:00.152946000Z",
"pKey" : "4",
"name" : "SEC_UAA_USER_CREATE",
"description" : "Permission to create Users"
}, {
"@class" : "org.openwms.core.uaa.api.SecurityObjectVO",
"ol" : 1,
"createDt" : "2025-02-04T23:10:00.152946000Z",
"lastModifiedDt" : "2025-02-04T23:10:00.152946000Z",
"pKey" : "3",
"name" : "SEC_UAA_USER_LOOKUP",
"description" : "Permission to find Users"
}, {
"@class" : "org.openwms.core.uaa.api.SecurityObjectVO",
"ol" : 1,
"createDt" : "2025-02-04T23:10:00.152946000Z",
"lastModifiedDt" : "2025-02-04T23:10:00.152946000Z",
"pKey" : "6",
"name" : "SEC_UAA_USER_DELETE",
"description" : "Permission to delete Users"
} ]
} ]
Find all Grants that belong to a User
A client might ask for all Grants
that are assigned to a User
resource. Therefore the client needs to query all grants
of the primary
User
:
Unresolved directive in 2-users.adoc - include::/home/runner/work/org.openwms.core.uaa.lib/org.openwms.core.uaa.lib/target/generated-snippets/user-findGrantsOfUser/http-request.adoc[]
and get an array of Grants
back, that could also be empty:
Unresolved directive in 2-users.adoc - include::/home/runner/work/org.openwms.core.uaa.lib/org.openwms.core.uaa.lib/target/generated-snippets/user-findGrantsOfUser/http-response.adoc[]
Modify an existing User
An existing User
instance can be modified by sending a PUT
request with the User
representation as request body.
PUT /users HTTP/1.1
Content-Type: application/json
Content-Length: 233
Host: localhost:8080
{
"links" : [ ],
"pKey" : "96baa849-dd19-4b19-8c5e-895d3b7f405e",
"username" : "superuser",
"locked" : true,
"enabled" : false,
"emailAddresses" : [ {
"emailAddress" : "admin@example.com",
"primary" : true
} ]
}
If the server has correctly updated the User
the response is a:
HTTP/1.1 200 OK
Content-Type: application/vnd.openwms.uaa.user-v1+json
Content-Length: 466
{
"ol" : 0,
"createDt" : "2020-06-22T19:02:47.404000000Z",
"lastModifiedDt" : "2025-02-04T23:09:55.107127000Z",
"pKey" : "96baa849-dd19-4b19-8c5e-895d3b7f405e",
"username" : "superuser",
"externalUser" : false,
"locked" : true,
"enabled" : false,
"emailAddresses" : [ {
"emailAddress" : "admin@example.com",
"primary" : true
} ],
"roleNames" : [ ],
"password" : "{bcrypt}$2a$15$baURCfRsoxem.eOv0IJDsup.9wEmHdiw.j8f0RaMflDbFnQWNipvG"
}
Change the Users password
Send a POST
request to the Users
password attribute to set or change the password of an that User
.
POST /users/96baa849-dd19-4b19-8c5e-895d3b7f405e/password HTTP/1.1
Content-Type: application/json
Content-Length: 28
Host: localhost:8080
{
"password" : "welcome"
}
If the server has successfully set the password the response looks like:
HTTP/1.1 200 OK
Content-Type: application/vnd.openwms.uaa.user-v1+json
Content-Length: 534
{
"ol" : 3,
"createDt" : "2020-06-22T19:02:47.404000000Z",
"lastModifiedDt" : "2025-02-04T23:09:55.209838000Z",
"pKey" : "96baa849-dd19-4b19-8c5e-895d3b7f405e",
"username" : "superuser",
"externalUser" : false,
"lastPasswordChange" : "2025-02-04T23:09:57Z",
"locked" : true,
"enabled" : false,
"details" : { },
"emailAddresses" : [ {
"emailAddress" : "admin@example.com",
"primary" : true
} ],
"roleNames" : [ ],
"password" : "{bcrypt}$2a$04$2/u284AalYZQuuhVnqqBGuGsnT.7lvw7CtgjIb1GFzQ0bEaxUVNQW"
}
Update the image of an existing User
To set the image of an existing User
a client needs to send a PATCH
request along the image in the UserDetails
.
POST /users/96baa849-dd19-4b19-8c5e-895d3b7f405e/details/image HTTP/1.1
Content-Type: application/octet-stream
Content-Length: 18572
Host: localhost:8080
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
If the server has correctly updated the Users
image the response looks like:
HTTP/1.1 200 OK
Delete an User
To finally delete all User
data a DELETE
request with the persistent key of the User
is required:
DELETE /users/96baa849-dd19-4b19-8c5e-895d3b7f405e HTTP/1.1
Host: localhost:8080
If the User
is not assigned somewhere else (in Roles
) and it has been deleted successfully the server responds:
HTTP/1.1 204 No Content
Role
An User
could be assigned to multiple Roles
and act on behalf of a Role
. Additionally a Role
assigns Grants
to all the Users
that are assigned to this Role
. By doing so, a Role
is also a group of Grants
that can be assigned to multiple Users
.
Role Index
An overview of all possible operations on Roles
can be found on the Role
index page that is retrieved with a GET
request:
GET /roles/index HTTP/1.1
Host: localhost:8080
And the server responds with a HAL+JSON
representation to further operations:
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 806
{
"_links" : {
"roles-findbypkey" : {
"href" : "http://localhost:8080/roles/pKey"
},
"roles-findall" : {
"href" : "http://localhost:8080/roles"
},
"roles-findusersofrole" : {
"href" : "http://localhost:8080/roles/pKey/users"
},
"roles-findgrantsofrole" : {
"href" : "http://localhost:8080/roles/pKey/grants"
},
"roles-create" : {
"href" : "http://localhost:8080/roles"
},
"roles-save" : {
"href" : "http://localhost:8080/roles/pKey"
},
"roles-delete" : {
"href" : "http://localhost:8080/roles/pKey"
},
"roles-assignuser" : {
"href" : "http://localhost:8080/roles/pKey/users/userPKey"
},
"roles-unassignuser" : {
"href" : "http://localhost:8080/roles/pKey/users/userPKey"
}
}
}
Create a Role
To create a new Role
instance, a POST
request must be send to the server with the mandatory fields of the Role
resource in the
request body.
POST /roles HTTP/1.1
Content-Type: application/json
Content-Length: 139
Host: localhost:8080
{
"@class" : "org.openwms.core.uaa.api.RoleVO",
"ol" : 0,
"name" : "ROLE_DEV",
"description" : "Developers",
"immutable" : true
}
Path | Type | Description |
---|---|---|
|
|
Technical versioning field to check the instance version |
|
|
Unique name of the Role |
|
|
Whether or not this Role is immutable. Immutable Roles can’t be modified |
|
|
A descriptive text for the Role |
If the Role
has been created successfully, the server returns the URI to the created resource in the Location
header:
HTTP/1.1 201 Created
Location: http://localhost:8080/roles/1236acae-356d-4e6e-ba06-c8b0f69e13d7
Content-Type: application/vnd.openwms.uaa.role-v1+json
Content-Length: 548
{
"@class" : "org.openwms.core.uaa.api.RoleVO",
"_links" : {
"users" : {
"href" : "http://localhost:8080/roles/1236acae-356d-4e6e-ba06-c8b0f69e13d7/users"
},
"grants" : {
"href" : "http://localhost:8080/roles/1236acae-356d-4e6e-ba06-c8b0f69e13d7/grants"
},
"role-findbypkey" : {
"href" : "http://localhost:8080/roles/1236acae-356d-4e6e-ba06-c8b0f69e13d7"
}
},
"ol" : 0,
"pKey" : "1236acae-356d-4e6e-ba06-c8b0f69e13d7",
"name" : "ROLE_DEV",
"description" : "Developers",
"immutable" : true
}
If a Role
with the same name already exists the server returns an error:
HTTP/1.1 409 Conflict
Content-Type: application/hal+json
Content-Length: 121
{
"message" : "Role with name [ROLE_ADMIN] already exists",
"messageKey" : "already.exists",
"httpStatus" : "409"
}
Find all Roles
To find and retrieve an array of all existing Roles
a role may call a GET
request:
GET /roles HTTP/1.1
Host: localhost:8080
and returns either an array of Roles
or an empty array, but always a 200-OK
.
HTTP/1.1 200 OK
Content-Type: application/vnd.openwms.uaa.role-v1+json
Content-Length: 844
[ {
"@class" : "org.openwms.core.uaa.api.RoleVO",
"links" : [ {
"rel" : "users",
"href" : "http://localhost:8080/roles/1/users"
}, {
"rel" : "grants",
"href" : "http://localhost:8080/roles/1/grants"
}, {
"rel" : "role-findbypkey",
"href" : "http://localhost:8080/roles/1"
} ],
"ol" : 1,
"pKey" : "1",
"name" : "ROLE_ADMIN",
"description" : "Super user role",
"immutable" : true
}, {
"@class" : "org.openwms.core.uaa.api.RoleVO",
"links" : [ {
"rel" : "users",
"href" : "http://localhost:8080/roles/2/users"
}, {
"rel" : "grants",
"href" : "http://localhost:8080/roles/2/grants"
}, {
"rel" : "role-findbypkey",
"href" : "http://localhost:8080/roles/2"
} ],
"ol" : 1,
"pKey" : "2",
"name" : "ROLE_OPS",
"description" : "Operator role",
"immutable" : true
} ]
Find a Role by persistent key
Each Role
has an unique ID the pKey or persistent identifier. To find and return a Role
by pKey
a client must send a GET
request
to the Roles
resource:
GET /roles/1 HTTP/1.1
Host: localhost:8080
HTTP/1.1 200 OK
Content-Type: application/vnd.openwms.uaa.role-v1+json
Content-Length: 415
{
"@class" : "org.openwms.core.uaa.api.RoleVO",
"_links" : {
"users" : {
"href" : "http://localhost:8080/roles/1/users"
},
"grants" : {
"href" : "http://localhost:8080/roles/1/grants"
},
"role-findbypkey" : {
"href" : "http://localhost:8080/roles/1"
}
},
"ol" : 1,
"pKey" : "1",
"name" : "ROLE_ADMIN",
"description" : "Super user role",
"immutable" : true
}
Find all Users that are assigned to a Role
A client might ask for all Users
that are assigned to a Role
resource. Therefore the client needs to query all users
of the primary
Role
:
GET /roles/1/users HTTP/1.1
Host: localhost:8080
and get an array of Users
back, that could also be empty:
HTTP/1.1 200 OK
Content-Type: application/vnd.openwms.uaa.user-v1+json
Content-Length: 779
[ {
"links" : [ ],
"ol" : 1,
"createDt" : "2020-06-22T19:02:47.404000000Z",
"lastModifiedDt" : "2025-02-04T23:09:49.366583000Z",
"pKey" : "96baa849-dd19-4b19-8c5e-895d3b7f405d",
"username" : "jenkins",
"externalUser" : true,
"lastPasswordChange" : "2020-06-22T19:02:47Z",
"locked" : true,
"enabled" : true,
"expirationDate" : "2020-06-23T19:02:45Z",
"fullname" : "Mister Jenkins",
"details" : { },
"emailAddresses" : [ {
"emailAddress" : "admin.private@acme.com",
"primary" : true,
"fullname" : "Mr. Jenkins"
}, {
"emailAddress" : "admin@acme.com",
"primary" : false,
"fullname" : "Mr. Jenkins"
} ],
"roleNames" : [ "ROLE_ADMIN" ],
"password" : "{bcrypt}$2a$15$baURCfRsoxem.eOv0IJDsup.9wEmHdiw.j8f0RaMflDbFnQWNipvG"
} ]
Find all Grants that belong to a Role
A client might ask for all Grants
that are assigned to a Role
resource. Therefore the client needs to query all grants
of the primary
Role
:
GET /roles/1/grants HTTP/1.1
Host: localhost:8080
and get an array of Grants
back, that could also be empty:
HTTP/1.1 200 OK
Content-Type: application/vnd.openwms.uaa.security-object-v1+json
Content-Length: 1104
[ {
"@class" : "org.openwms.core.uaa.api.SecurityObjectVO",
"ol" : 1,
"createDt" : "2025-02-04T23:09:49.618254000Z",
"lastModifiedDt" : "2025-02-04T23:09:49.618254000Z",
"pKey" : "5",
"name" : "SEC_UAA_USER_MODIFY",
"description" : "Permission to modify Users"
}, {
"@class" : "org.openwms.core.uaa.api.SecurityObjectVO",
"ol" : 1,
"createDt" : "2025-02-04T23:09:49.618254000Z",
"lastModifiedDt" : "2025-02-04T23:09:49.618254000Z",
"pKey" : "4",
"name" : "SEC_UAA_USER_CREATE",
"description" : "Permission to create Users"
}, {
"@class" : "org.openwms.core.uaa.api.SecurityObjectVO",
"ol" : 1,
"createDt" : "2025-02-04T23:09:49.618254000Z",
"lastModifiedDt" : "2025-02-04T23:09:49.618254000Z",
"pKey" : "3",
"name" : "SEC_UAA_USER_LOOKUP",
"description" : "Permission to find Users"
}, {
"@class" : "org.openwms.core.uaa.api.SecurityObjectVO",
"ol" : 1,
"createDt" : "2025-02-04T23:09:49.618254000Z",
"lastModifiedDt" : "2025-02-04T23:09:49.618254000Z",
"pKey" : "6",
"name" : "SEC_UAA_USER_DELETE",
"description" : "Permission to delete Users"
} ]
Modify an existing Role
An existing Role
instance can be modified by sending a PUT
request with the Role
representation as request body. At least the name of
the Role
, as an identifying attribute must be set.
PUT /roles/1 HTTP/1.1
Content-Type: application/json
Content-Length: 167
Host: localhost:8080
{
"@class" : "org.openwms.core.uaa.api.RoleVO",
"ol" : 0,
"pKey" : "1",
"name" : "ROLE_SUPER",
"description" : "Administrators role",
"immutable" : false
}
Path | Type | Description |
---|---|---|
|
|
The persistent key must be passed when modifying an existing instance |
|
|
Technical versioning field to check the instance version |
|
|
The name as an identifying attribute of the existing Role, cannot be changed |
|
|
A description text to update |
|
|
Whether the Role is immutable or not |
If the server has correctly updated the Role
the response contains the updated representation:
HTTP/1.1 200 OK
Content-Type: application/vnd.openwms.uaa.role-v1+json
Content-Length: 419
{
"@class" : "org.openwms.core.uaa.api.RoleVO",
"_links" : {
"users" : {
"href" : "http://localhost:8080/roles/1/users"
},
"grants" : {
"href" : "http://localhost:8080/roles/1/grants"
},
"role-findbypkey" : {
"href" : "http://localhost:8080/roles/1"
}
},
"ol" : 1,
"pKey" : "1",
"name" : "ROLE_SUPER",
"description" : "Administrators role",
"immutable" : true
}
If the name of the Role
to update is missing, the server responds with an error:
HTTP/1.1 400 Bad Request
Content-Type: application/hal+json
Content-Length: 143
{
"message" : "Error on validating the input parameters [save.role.name]",
"messageKey" : "core.validation.error",
"httpStatus" : "400"
}
Assign an User to a Role
Users
can be assigned to one or more Roles
. To assign an existing User
to an existing Role
the client must send a POST
request
to the primary Role
resource:
POST /roles/1/users/96baa849-dd19-4b19-8c5e-895d3b7f405e HTTP/1.1
Host: localhost:8080
Content-Type: application/x-www-form-urlencoded
If the User
has been assigned successfully, the server responds with 200-OK
:
HTTP/1.1 200 OK
Content-Type: application/vnd.openwms.uaa.role-v1+json
Content-Length: 415
{
"@class" : "org.openwms.core.uaa.api.RoleVO",
"_links" : {
"users" : {
"href" : "http://localhost:8080/roles/1/users"
},
"grants" : {
"href" : "http://localhost:8080/roles/1/grants"
},
"role-findbypkey" : {
"href" : "http://localhost:8080/roles/1"
}
},
"ol" : 1,
"pKey" : "1",
"name" : "ROLE_ADMIN",
"description" : "Super user role",
"immutable" : true
}
If the User
or the Role
do not exist the server responds with an error:
HTTP/1.1 404 Not Found
Content-Type: application/hal+json
Content-Length: 166
{
"message" : "User with ID UNKNOWN does not exist",
"messageKey" : "user.pkey.not.exist",
"obj" : [ "UNKNOWN" ],
"httpStatus" : "404",
"class" : "String"
}
Unassign an User from a Role
Already assigned Users
can be unassigned from a Role
. Therefore the client sends a DELETE
request on the secondary User
resource of
the primary Role
resource. Note: This will not delete the User
but delete the assignment between the Role
and the User
.
DELETE /roles/1/users/96baa849-dd19-4b19-8c5e-895d3b7f405d HTTP/1.1
Host: localhost:8080
If the User
has been unassigned successfully, the server responds with 200-OK
:
HTTP/1.1 200 OK
Content-Type: application/vnd.openwms.uaa.role-v1+json
Content-Length: 415
{
"@class" : "org.openwms.core.uaa.api.RoleVO",
"_links" : {
"users" : {
"href" : "http://localhost:8080/roles/1/users"
},
"grants" : {
"href" : "http://localhost:8080/roles/1/grants"
},
"role-findbypkey" : {
"href" : "http://localhost:8080/roles/1"
}
},
"ol" : 1,
"pKey" : "1",
"name" : "ROLE_ADMIN",
"description" : "Super user role",
"immutable" : true
}
If the User
or the Role
do not exist the server responds with an error:
HTTP/1.1 404 Not Found
Content-Type: application/hal+json
Content-Length: 166
{
"message" : "Role with ID UNKNOWN does not exist",
"messageKey" : "role.pkey.not.exist",
"obj" : [ "UNKNOWN" ],
"httpStatus" : "404",
"class" : "String"
}
Delete a Role
To finally delete all Role
data, a DELETE
request with the persistent key of the Role
is required:
DELETE /roles/1 HTTP/1.1
Host: localhost:8080
If the Role
has been deleted successfully the server responds:
HTTP/1.1 204 No Content
Grant
A Grant
represents a permission to perform an action. A Grant
can be assigned to a Role
and is always tied to some kind of action that
can be taken. It has a unique business key, that is used in API or UI to protect against unauthorized access.
Grant Index
An overview of all possible operations on Grants
can be found on the Grant
index page that is retrieved with a GET
request:
GET /grants/index HTTP/1.1
Host: localhost:8080
And the server responds with a HAL+JSON
representation to further operations:
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 343
{
"_links" : {
"grant-findbypkey" : {
"href" : "http://localhost:8080/grants/pKey"
},
"grant-findall" : {
"href" : "http://localhost:8080/grants"
},
"grant-findallforuser" : {
"href" : "http://localhost:8080/grants"
},
"grant-create" : {
"href" : "http://localhost:8080/grants"
}
}
}
Create a Grant
To create a new Grant
instance, a POST
request must be send to the server with the mandatory fields of the Grant
resource in the
request body.
POST /grants HTTP/1.1
Content-Type: application/json
Content-Length: 132
Host: localhost:8080
{
"@class" : "org.openwms.core.uaa.api.GrantVO",
"name" : "VIEW_USERS",
"description" : "Permission to view all users in UI"
}
Not named properties are optional to pass.
Path | Type | Description |
---|---|---|
|
|
Unique name of the Grant |
|
|
(Optional) A descriptive text for the Grant |
If the Grant
has been created successfully, the server returns the URI to the created resource in the Location
header:
HTTP/1.1 201 Created
Location: http://localhost:8080/grants/b423c558-bc99-4328-8dc6-328d5531e2b3
Content-Type: application/vnd.openwms.uaa.grant-v1+json
Content-Length: 435
{
"@class" : "org.openwms.core.uaa.api.GrantVO",
"_links" : {
"grant-findbypkey" : {
"href" : "http://localhost:8080/grants/b423c558-bc99-4328-8dc6-328d5531e2b3"
}
},
"ol" : 0,
"createDt" : "2025-02-04T23:10:00.244818148Z",
"lastModifiedDt" : "2025-02-04T23:10:00.244818148Z",
"pKey" : "b423c558-bc99-4328-8dc6-328d5531e2b3",
"name" : "VIEW_USERS",
"description" : "Permission to view all users in UI"
}
If a Grant
with the same name already exists the server returns an error:
HTTP/1.1 409 Conflict
Content-Type: application/hal+json
Content-Length: 140
{
"message" : "Grant with name SEC_UAA_USER_LOOKUP already exists",
"messageKey" : "grant.name.already.exists",
"httpStatus" : "409"
}
Find all Grants
To retrieve all existing Grants
from the server, a client simply needs to do a GET
request to the Grants
resource.
GET /grants HTTP/1.1
Host: localhost:8080
The server responds with a list representation of all Grants
or an empty list:
HTTP/1.1 200 OK
Content-Type: application/vnd.openwms.uaa.grant-v1+json
Content-Length: 1472
[ {
"@class" : "org.openwms.core.uaa.api.GrantVO",
"links" : [ {
"rel" : "grant-findbypkey",
"href" : "http://localhost:8080/grants/3"
} ],
"ol" : 1,
"createDt" : "2025-02-04T23:10:00.287469000Z",
"lastModifiedDt" : "2025-02-04T23:10:00.287469000Z",
"pKey" : "3",
"name" : "SEC_UAA_USER_LOOKUP",
"description" : "Permission to find Users"
}, {
"@class" : "org.openwms.core.uaa.api.GrantVO",
"links" : [ {
"rel" : "grant-findbypkey",
"href" : "http://localhost:8080/grants/4"
} ],
"ol" : 1,
"createDt" : "2025-02-04T23:10:00.287469000Z",
"lastModifiedDt" : "2025-02-04T23:10:00.287469000Z",
"pKey" : "4",
"name" : "SEC_UAA_USER_CREATE",
"description" : "Permission to create Users"
}, {
"@class" : "org.openwms.core.uaa.api.GrantVO",
"links" : [ {
"rel" : "grant-findbypkey",
"href" : "http://localhost:8080/grants/5"
} ],
"ol" : 1,
"createDt" : "2025-02-04T23:10:00.287469000Z",
"lastModifiedDt" : "2025-02-04T23:10:00.287469000Z",
"pKey" : "5",
"name" : "SEC_UAA_USER_MODIFY",
"description" : "Permission to modify Users"
}, {
"@class" : "org.openwms.core.uaa.api.GrantVO",
"links" : [ {
"rel" : "grant-findbypkey",
"href" : "http://localhost:8080/grants/6"
} ],
"ol" : 1,
"createDt" : "2025-02-04T23:10:00.287469000Z",
"lastModifiedDt" : "2025-02-04T23:10:00.287469000Z",
"pKey" : "6",
"name" : "SEC_UAA_USER_DELETE",
"description" : "Permission to delete Users"
} ]
Find a Grant by persistent key
Each Grant
has an unique ID the pKey or persistent identifier. To find and return a Grant
by pKey
a client must send a GET
request to the Grants
resource:
GET /grants/3 HTTP/1.1
Host: localhost:8080
HTTP/1.1 200 OK
Content-Type: application/vnd.openwms.uaa.grant-v1+json
Content-Length: 364
{
"@class" : "org.openwms.core.uaa.api.GrantVO",
"_links" : {
"grant-findbypkey" : {
"href" : "http://localhost:8080/grants/3"
}
},
"ol" : 1,
"createDt" : "2025-02-04T23:10:00.342152000Z",
"lastModifiedDt" : "2025-02-04T23:10:00.342152000Z",
"pKey" : "3",
"name" : "SEC_UAA_USER_LOOKUP",
"description" : "Permission to find Users"
}
Path | Type | Description |
---|---|---|
|
|
Type identifier of the Grant type |
|
|
Technical versioning field to check the instance version |
|
|
The technical persistent identifier of the Grant |
|
|
When the record has been created |
|
|
Timestamp when the record has been updated the last time |
|
|
Unique name of the Grant |
|
|
A descriptive text for the Grant |
Find all Grants of a User
To retrieve all existing Grants
from assigned to a User
, a client simply needs to do a GET
request to the Grants
resource and pass
the users identity within the X-Identity
http header.
GET /grants HTTP/1.1
X-Identity: jenkins
Host: localhost:8080
The server responds with a list representation of all Grants
:
HTTP/1.1 200 OK
Content-Type: application/vnd.openwms.uaa.grant-v1+json
Content-Length: 1472
[ {
"@class" : "org.openwms.core.uaa.api.GrantVO",
"links" : [ {
"rel" : "grant-findbypkey",
"href" : "http://localhost:8080/grants/5"
} ],
"ol" : 1,
"createDt" : "2025-02-04T23:10:00.379610000Z",
"lastModifiedDt" : "2025-02-04T23:10:00.379610000Z",
"pKey" : "5",
"name" : "SEC_UAA_USER_MODIFY",
"description" : "Permission to modify Users"
}, {
"@class" : "org.openwms.core.uaa.api.GrantVO",
"links" : [ {
"rel" : "grant-findbypkey",
"href" : "http://localhost:8080/grants/4"
} ],
"ol" : 1,
"createDt" : "2025-02-04T23:10:00.379610000Z",
"lastModifiedDt" : "2025-02-04T23:10:00.379610000Z",
"pKey" : "4",
"name" : "SEC_UAA_USER_CREATE",
"description" : "Permission to create Users"
}, {
"@class" : "org.openwms.core.uaa.api.GrantVO",
"links" : [ {
"rel" : "grant-findbypkey",
"href" : "http://localhost:8080/grants/3"
} ],
"ol" : 1,
"createDt" : "2025-02-04T23:10:00.379610000Z",
"lastModifiedDt" : "2025-02-04T23:10:00.379610000Z",
"pKey" : "3",
"name" : "SEC_UAA_USER_LOOKUP",
"description" : "Permission to find Users"
}, {
"@class" : "org.openwms.core.uaa.api.GrantVO",
"links" : [ {
"rel" : "grant-findbypkey",
"href" : "http://localhost:8080/grants/6"
} ],
"ol" : 1,
"createDt" : "2025-02-04T23:10:00.379610000Z",
"lastModifiedDt" : "2025-02-04T23:10:00.379610000Z",
"pKey" : "6",
"name" : "SEC_UAA_USER_DELETE",
"description" : "Permission to delete Users"
} ]
or a HTTP 204-NO CONTENT
response if no Grants
are assigned to the User
:
HTTP/1.1 204 No Content
or a HTTP 404-NOT FOUND
response if the User
does not exist:
HTTP/1.1 404 Not Found
Content-Type: application/hal+json
Content-Length: 121
{
"message" : "User with name UNKNOWN does not exist",
"messageKey" : "user.name.not.exist",
"httpStatus" : "404"
}