Specification/0.5

From RestAuth
Jump to navigation Jump to search

This document specifies RestAuth, a simple protocol that may be used for implementing shared authentication, authorization and preferences. It is (loosely) based on the REST Paradigm[i 1] with some deviations to ease protocol implementation.

Status

This page represents version 0.5 of the RestAuth standard. This version was released August 28, 2011.

Copyright

Copyright (C) Mathias Ertl (2010, 2011)


Introduction

RestAuth defines an HTTP based protocol intended to enable shared authentication, authorization and preferences. The primary design goals are the use of established Internet standards and ease of implementation, both on the client and on the server side.

Statelessness

As with any protocol based on the REST paradigm[i 1], RestAuth is a stateless protocol. This also means that the system does not implement transactions of any kind. For example, a user that exists in the first request is not guaranteed to exist in a second request a second later.

Data types

This document specifies an HTTP interface with the body of the request/response containing the relevant data. The protocol specification is agnostic to data formats. This document instead defines three simple abstract data types and provides mappings to common Internet data formats (see Mapping abstract data types to concrete data types).

String

A simple string as found in most programming languages. In general this is a UTF-8 string and the format itself does not pose any restrictions on used characters. An implementing service may impose some restrictions, especially when handling usernames (see Restrictions on entity names).

Dictionary

Any number of key/value pairs, each key and value being a string.

List

A list of strings, used when returning multiple items (usually identifiers for entities) at once.

Standards

The RestAuth protocol builds upon several different Internet standards. Defined here are standards and versions thereof that any implementing client or server is required to implement:

  • Hypertext Transfer Protocol -- HTTP/1.1[n 1][i 2]
  • HTTP Authentication: Basic and Digest Access Authentication[n 2]
  • The application/json Media Type for JavaScript Object Notation (JSON)[n 3][i 3]
  • The UTF-8[n 4][i 4] character encoding scheme


Notation

If request strings include a value dependent on the context, this value is enclosed in angle brackets. For example, if the client wants to do a request for the properties of the user example, it does a GET request to /users/example/props/. The specification specifies to do a request to /users/<username>/props/.

Protocol framework

The RestAuth protocol is based upon HTTP 1.1[n 1]. This section defines common headers that have to be included in all or most requests and/or responses as well as error status codes that may be returned by a server implementation.

Illegal characters for entities

ASCII control characters (hex codes <=31 and 127) are illegal in both entity names and values.

Restrictions on entity names

In addition to characters generally disallowed, the following ASCII characters are illegal for any entity name (names for users, groups or properties):

char ASCII hex code
/ 2F
: 3A
\ 5C

All entity names must be case insensitive. The RestAuth service is responsible for lower-casing entity names upon creation and during queries.

A RestAuth service may introduce additional practical restrictions on usernames. This may include additional invalid characters or a minimum or maximum length.

Security considerations

Since a RestAuth service stores sensitive information, security is of the utmost importance. For a server implementation to be standards compliant, several security criteria have to be met:

Use of SSL

Both clients and servers must use HTTPS exclusively. Clients or client libraries must not support HTTP without SSL. Server implementations must not offer pure HTTP connections if the server provides its own web server.

Configuration examples, etc., have to assume that HTTPS is used.

If clients are themselves servers (i.e. a Content Management System), they should use SSL for all traffic that transmits passwords or secret session data (i.e. HTTP cookies).

Password hashes

A server implementation must store passwords hashed with a secure hashing algorithm. In particular, MD5 is no longer considered secure.

The use of SHA-1 or stronger hashing algorithms is recommended.

Service authentication

RestAuth service implementations must require the use of an HTTP authentication mechanism as defined in "HTTP Authentication: Basic and Digest Access Authentication"[n 2] on all requests. Both servers and clients must support Basic Access Authentication[n 5], support for Digest Access Authentication[n 6] is optional.

Note: Do not confuse the username and password used in request authentication with the usernames and passwords that are shared between services and stored in a RestAuth implementation.

Content encoding

Both request and response bodies must be UTF-8[n 7][i 4] encoded.

Request headers

Accept header

All requests SHOULD include an Accept header[n 8] indicating media types acceptable by the client.

If the server needs to generate a response (when returning a 200 OK status code) and the header does not specify any media type the server can generate, it MUST return a 406 Not Acceptable status code. If the server does not need to generate a response body (as with a 201 Created or 204 No Content status code) it might ignore a missing Accept header.

If the header is missing, the server may return a 406 Not Acceptable status code or assume a default media type.

Content-Type header

Every POST[n 9] or PUT[n 10] request MUST include a Content-Type[n 11] header.

If the header indicates a content-type not supported by the server or is missing, it MUST return a 415 Unsupported Media Type. If the content is not parsable as the type indicated by this header, the server MUST return a 400 Bad Request status code.

Response headers

Content-Type header

Every response except for 204 No Content must include a Content-Type header.

The Content-Type of the response MUST be one indicated by the Accept header send in the original request. If the request gives a wildcard, the server can use some sensible default.

Resource-Type header

If the server returns a 404 Not Found, it must include the Resource-Type header, which must indicate the type of resource not found. The value must be one of user, group or property. If the request URI addressed multiple resources at once (i.e. when getting a user property), the value of the header must be the first resource addressed in the URI.

Response codes

This section lists response codes the server may return on any or most requests. Requests that may be returned by any request are 401 Unauthorized, 406 Not Acceptable and 500 Internal Server Error. The status codes 400 Bad Request, 411 Length Required and 415 Unsupported Media Type may occur with any POST or PUT request. Apart from these status codes, the specification on individual requests gives an authoritative list of status codes returned by each individual request.

200 OK

The general status code that should be returned upon successfully processing a request is 200 OK[n 12].

201 Created

A RestAuth service must respond with status code 201 Created[n 13] if the request created a new resource. This status code must only occur with POST or PUT requests.

Note that as by the HTTP/1.1 specification[n 1], responses of this type must include both a Location header and a response body giving the URI under which the newly created resource can be addressed. The presence of a response body infers the presence of a Content-Type header.

204 No Content

A RestAuth service must respond with status code 204 No Content[n 14] if the request only verifies the existence of the addressed entity or if an entity was successfully updated.

Note that by definition, this response must not include a response body. Please see the referenced HTTP specification for details.

400 Bad Request

The RestAuth service must respond with status code 400 Bad Request[n 15] if

  • the request body could not be parsed as the content-type indicated by the Content-Type header
  • the request body was parsable but did not contain the parameters expected.

Since this status code addresses the request body and only POST[n 9] and PUT[n 10] requests have such a body, this status code only occurs with requests of type POST or PUT.

401 Unauthorized

The RestAuth service must respond with status code 401 Unauthorized[n 16] if the client failed to authenticate itself. The WWW-Authenticate header must be present in such a response and include at least a Basic Authentication[n 5] challenge. A Digest Authentication[n 6] may also be present but is optional.

This status code may occur with requests of any type and at any URI.

404 Not Found

The RestAuth service must respond with status code 404 Not Found[n 17] if a resource accessed by the request does not exist. In case of this response code, the Resource-Type header must exist and indicate the type of the resource not found.

This status code must not occur with a request that does not address an individual entity. In particular, this includes:

  • requests meant to return a list of entities (i.e. querying all users: GET /users). If there are no entities defined, the service must return an empty list.
  • requests meant to add an entity to a an existing collection (i.e. adding a user: POST /users/). If the entity is already defined, the service must return 409 Conflict.

Note: Since 404 Not Found is the standard response code for pages not found, you are likely to encounter this error if your request uses an invalid path, i.e. to /userrs/, /ussers/ or so.

406 Not Acceptable

The RestAuth service must respond with status code 406 Not Acceptable[n 18] if the service cannot generate a response in any of the data formats indicated by the Accept header. If the header is not present at all, the server may return this status code or assume a sensible default.

If the specification specifies a status code that does not include a message body in case of success (201 Created or 204 No Content), the RestAuth service may ignore a missing Accept header.

409 Conflict

The RestAuth service must respond with status code 409 Conflict[n 19] if the request attempts to create an entity that is already defined.

This status code can only occur on top-level POST requests, currently only creating users, properties or groups.

411 Length Required

The RestAuth service must respond with status code 411 Length Required[n 20] if a POST or PUT request does not have a Content-Length header.

Since this status code addresses the request body and only POST[n 9] and PUT[n 10] requests have such a body, this status code only occurs with requests of type POST or PUT.

412 Precondition Failed

The RestAuth service must respond with status code 412 Precondition Failed[n 21] if a requests attempts to update a resource to a value not acceptable to the system. In particular, this includes unacceptable (too short, unacceptable characters, ...) usernames or passwords.

415 Unsupported Media Type

When receiving a POST or PUT request, a RestAuth service MUST return status code 415 Unsupported Media Type[n 22] if the request does not include a Content-Type header or if the header indicates a media type unsupported by the server implementation.

This status code only occurs with POST[n 9] or PUT[n 10] requests.

500 Internal Server Error

The RestAuth service may return status code 500 Internal Server Error[n 23] if any internal error occurs.

Managing users

RestAuth tries to make it as simple as possible to implement basic user authentication. A user described in this section consists of nothing more but a unique name (which is used as a unique identifier in all requests) and a password, it has no properties or groups. This section just specifies the very basic user management operations.

Because of the simplicity of the task, all requests except getting a list of users do not require any response body - it is enough to know the response code.

Get a list of users

To get a list of all users known to the system, the client does a GET request to /users/.

The server must respond with a list of usernames known to it. The response code must be 200 OK if no internal error occurs.

Create a user

To create a new user, the client does a POST request to /users/. The request body must be a dictionary, that must include the name of the user and can optionally include a password and initial properties.

key value type of value
Mandatory parameters
user The name of the user. String
Optional parameters
password The password for the user. If the parameter is not included, the user does not have a password and is unable to log in. Consequently, every password verification request must return with 404 Not Found. Passing a Null value is equal to not passing the parameter. String or Null
properties Initial properties, where keys represent the name of a property and their respective value represents the value of that property. Dictionary


The server must respond with status code 201 Created if the user is successfully created and with 409 Conflict it the user already exists.

The minimum requirements on usernames do apply for this request. The service may enforce additional requirements on usernames and/or passwords. If the submitted data does not meet any of these requirements (as well as the minimum requirements on usernames), the server must respond with a 412 Precondition Failed.

Verify that a user exists

To verify that a user exists, the client does a GET request to /users/<username>/.

The server must respond with status code 204 No Content if the user exists and 404 Not Found if not.

Verify password

To verify a users password, the client does a POST request to /users/<username>/. The request body must be a dictionary containing the password to verify:

key value
password The password to verify

The server must respond with status code 204 No Content if the user exists and the password is correct. If either the user does not exist or the password is not correct, the server must respond with status code 404 Not Found.

Note: Following the REST paradigm, this really should be a GET request, not a POST request. GET requests have one major disadvantage, though: GET parameters are usually logged in the log-files of a web server. This would mean that a password verification request to /users/<username>?password=<password> would be logged. There are ways around logging this, but services should always be "secure by default".

Change password

To change the password of a user, the client does a PUT request to /users/<username>/. The request body must be a dictionary containing the new password:

key value
Optional parameters
password The password to verify

If the password parameter is omitted or an empty string, the user has no password and should be unable to log in. Any password verification request must return with 404 Not Found.

The server must respond with status code 204 No Content if the password was successfully updated and with status code 404 Not Found if the user does not exist. If the service enforces additional requirements on passwords and the new password does meet any of these requirements, the server must respond with a 412 Precondition Failed.

Delete user

To delete a user, the client does a DELETE request to /users/<username>/.

The server must respond with status code 204 No Content if the user was deleted. If the user didn't exist, the server must respond with 404 Not Found.

Managing user properties

It is possible to use RestAuth to store user properties, commonly used for shared user preferences. Properties are just simple key/value pairs and both keys and values are completely arbitrary. The specification only gives recommendations about property names and a list of predefined property names for popular preferences.

A property and its value always only exists in the context of a specific user. Thus, the common prefix for all requests defined in this section is /users/<username>/props/ where <username> is of course the name of the user in this context.

Recommendations about property names

The RestAuth protocol does not define any mandatory conventions on protocol names, services may share properties with any name they like. There are however some "common sense" assumptions.

  • If a property is only useful within one specific application, consider storing the property locally. If you still want to save it in a RestAuth server, prefix it with the service name.
  • If a property is useful for multiple clients of the same type (i.e. several installations of the same content management system), prefix the preferences with a name for this type of system.
  • Only if preferences may be useful to multiple clients, use a simple name. You may want to consider mapping them to one of the predefined names.

Predefined property names

This section gives some recommendations about property names for some well known properties that are likely to occur in multiple systems.

key what
email Email address of the user
jid Jabber address of the user
full name Full name of the user. If possible, use 'first name' and 'full name' instead.
first name First name of the user.
last name Last name of the user.
language The preferred language of the user.

Get all properties

To get a list of all properties and their respective values for a user, the client performs a GET request to /users/<user>/props/.

The server must respond with status code 200 OK if the user exists. The response body must contain a dictionary, where the keys represent the name of the property and the value the value of that property. If the user is not found, the client must respond with 404 Not Found.

Create a new property

To create a new property for a user, the client performs a POST request to /users/<user>/props/. This request is intended for creating new properties where the client wants to be sure not to overwrite any old value.

The request body must be a dictionary with two key/value pairs:

key value
prop The name of the property to define
value The value for that property.

If the property is successfully created, the server must respond with status code 201 Created. If the property already exists, the server must respond with 409 Conflict. If the user is not found, the client must respond with 404 Not Found.

Get value of a property

To get the value for one specific property, the client performs a GET request to /users/<user>/props/<prop>/.

If the addressed user and property exists, the server must respond with 200 OK. The response body must contain a string representing the value of that property. If the user or the property does not exist, the server must respond with 404 Not Found.

Set value of a property

To set the value of a property (or create it, if it doesn't exist), the client performs a PUT request to /users/<user>/props/<prop>/. The request body must be a dictionary containing the new value:

key value
value The value of the new property

If the property was created by this request, the server must respond with status code 201 Created. If the property was previously defined, the server must respond with status code 200 OK and the response body must be a string representing the previous value of that property.

If the user is not found, the client must respond with 404 Not Found.

Delete property

To delete a property, the client does DELETE request to /users/<username>/props/<prop>/.

The server must respond with status code 204 No Content if the property was deleted. If the user or the property does not exist, the server must respond with 404 Not Found.

Managing user groups

It is possible to use RestAuth to store user groups, commonly used for shared authorization. Any user may be member of zero, one or multiple groups. The specification does not mandate any particular inheritance (see Nested groups) or visibility model (see Group visibility), thus clients might not be able to tell where any particular membership is coming from.

Meta-groups

A RestAuth implementation may provide meta-groups. The concept describes that one or more groups may be themselves member of a group, called a meta-group. A group that is a member of a meta-group inherits all memberships from it and is called a sub-group of the meta-group. The membership to a sub-group is said to be inherited if the user is a member of the meta-group and local if the user is a member of the sub-group. A meta-group may itself also be a member of a meta-meta-group.

One common use case is granting some users privileges in all clients and some other users in only a few clients. To achieve this, the RestAuth service could have a meta group. The meta-group is not used by any client directly, instead each client has its own group, each a sub-group of the meta-group, to manage the respective privilege(s). The meta-group contains all the users that should have the privilege for all clients, the sub-group only contains the users that should have this privilege in one individual client.

Implementation of meta-groups is optional (but recommended). If the RestAuth service implements meta-groups, it must provide adding a group to a group and removing a group from a group.

Group visibility

A RestAuth service may choose to implement groups in a way that they are local to the client creating and accessing them. A group from client A is hence not visible for client B and vice versa. Additionally, a group may not be associated by any service and thus not accessible by any service directly, potentially useful as meta-groups.

The implementation of group visibility does not change the interface in any way. But implementing group visibility together with meta-groups might lead to situation that the client is unable to tell the difference between a local and an inherited membership.

Get a list of groups

To get a list of all groups known to the system, the client does a GET request to /groups/.

The server must respond with a list of groups known to it. The response code must be 200 OK if no internal error occurs.

Create a group

To create a new user, the client does a POST request to /groups/. The request body must be a dictionary representing the name of the group:

key value
group The name of the group to create.


The server must respond with status code 201 Created if the group is successfully created and with 409 Conflict it the group already exists.

Verify that a group exists

To verify that a group exists, the client does a GET request to /groups/<groupname>/.

The server must respond with status code 204 No Content if the group exists and 404 Not Found if not.

Add a user to a group

To add a user to a group, the client performs a POST request to /groups/<groupname>/users/. The request body must be a dictionary containing the name of the user to add:

key value
user The name of the user to add.


The server must respond with status code 204 No Content if no error occurred (including if the user already was in the group). If the user or the group do not exist, the response code must be 404 Not Found.

Get all users in a group

To get a list of all users in a specified group, the client does a GET request to /groups/<groupname>/users/.

The server must respond with a list of users in the specified group. The response code must be 200 OK if the group exists or 404 Not Found if the group does not exist.

Get all groups of a user

To get a list of all groups known to the system, the client does a GET request to /groups/ with get GET parameter user=<username>.

The server must respond with a list of groups that the user is a member of. The response code must be 200 OK if no error occurs or with 404 Not Found if the user does not exist.

Verify that a user is in a group

To verify that a user is in a certain group, the client does a GET request to /groups/<groupname>/users/<username>/.

The server must respond with status code 204 No Content if the user is in the group and 404 Not Found if not. Note that the Resource-Type header must say 'user' even if the user exists and is just not in the respective group.

Remove a user from a group

To remove a user from a group, the client does a DELETE request to /groups/<groupname>/users/<username>/.

The server must respond with status code 204 No Content if the user was removed. If either user or group does not exist or the user is not a member of the group, it must respond with status code 404 Not Found.

Add a group to a group

To make a group meta-group of a group, the client does a POST request to /groups/<meta-groupname>/groups/. The request body must be a dictionary containing the name of the sub-group:

key value
group The name of the sub-group to add.


The server must respond with status code 204 No Content if the sub-group was successfully added. If either group does not exists, the server must respond with 404 Not Found.

Get a list of sub-groups

To get a list of sub-groups of a group, the client does a GET request to /groups/<groupname>/groups/.

The server must respond with a list of sub-groups. The response code must be 200 OK if the group exists or 404 Not Found if the group does not exist.

Remove a group from a group

To remove a sub-group of a group, the client does a DELETE request to /groups/<meta-groupname>/groups/<sub-groupname>/. This request is not intended to delete the sub-group entirely, it only removes the relation between sub- and meta-group.

The server must respond with status code 204 No Content if the sub-group was successfully removed. If either group does not exists or if the sub-group is not actually a sub-group, the server must respond with 404 Not Found.

Delete a group

To delete a group, the client does a DELETE request to /groups/<groupname>/.

The server must respond with status code 204 No Content if the user was deleted. If the group didn't exist, the server must respond with 404 Not Found.

Doing dry-runs

Some systems want to test if a specific operation would work at the given instant. Due to the statelessness of RestAuth and HTTP in general, a client can never guarantee i.e. that creating a user actually works after doing a dry-run of that operation as the user could have been created by a different client in the meantime.

In general, a dry-run is specified by prefixing the URL path with "/test/" and doing the same request. The request may return any status code that the corresponding non-dry-run request may return. A RestAuth implementation may support dry-runs for any operation that does a POST, PUT or DELETE request (except for verifying a password). The protocol mandates the support for dry-runs of the following operations:

  1. Creating a user
  2. Creating a property
  3. Creating a group

Mapping abstract data types to concrete data types

JavaScript Object Notation (JSON)

The generic data types map to the following JSON object types:

generic type JSON object type JSON example
String String "foobar"
Dictionary Object {"foo": "bar"}
List Array ["foo", "bar"]

For an definition of JSON object types please see the JSON format homepage[n 3]

Wrapping top-level objects

According to the JSON-Specification, only Arrays or Objects may be a top-level argument. If the specification mandates a different object, this object is to be wrapped in a list.

Related standards

Related protocols are Atom[i 5], a de facto reference implementation of the REST paradigm and of course various protocols and systems that compete in the field such as LDAP[i 6] or OpenID[i 7].

References

Normative references

  1. 1.0 1.1 1.2 Fielding, R., Gettys, J., Mogul, J., Frysyk, H., Masinter, L., Leach, P. and T. Berners-Lee, "Hypertext Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999.
  2. 2.0 2.1 Franks, J., Hallam-Baker, P., Hostetler, J., Lawrence, S., Leach, P., Luotonen, A., Sink, E. and L. Stewart, "HTTP Authentication: Basic and Digest Access Authentication", RFC 2617, June 1999.
  3. 3.0 3.1 Crockford, D., "The application/json Media Type for JavaScript Object Notation (JSON)", RFC 4627, July 2006.
  4. Yergeau, F., "UTF-8, a transformation format of ISO 10646", RFC 3629, November 2003.
  5. 5.0 5.1 Franks, et al., "HTTP Authentication: Basic and Digest Access Authentication", RFC 2617, Section 2, Basic Access Authentication Scheme
  6. 6.0 6.1 Franks, et al., "HTTP Authentication: Basic and Digest Access Authentication", RFC 2617, Section 3, Digest Access Authentication Scheme
  7. Yergeau, F., "UTF-8, a transformation format of ISO 10646", RFC 3629, November 2003
  8. Fielding, et al., "Hypertext Transfer Protocol -- HTTP/1.1", RFC 2616, Section 14.1, Accept
  9. 9.0 9.1 9.2 9.3 Fielding, et al., "Hypertext Transfer Protocol -- HTTP/1.1", RFC 2616, Section 9.5, POST
  10. 10.0 10.1 10.2 10.3 Fielding, et al., "Hypertext Transfer Protocol -- HTTP/1.1", RFC 2616, Section 9.6, PUT
  11. Fielding, et al., "Hypertext Transfer Protocol -- HTTP/1.1", RFC 2616, Section 14.11, Content-Type
  12. Fielding, et al., "Hypertext Transfer Protocol -- HTTP/1.1", RFC 2616, Section 10.2.1, 200 OK
  13. Fielding, et al., "Hypertext Transfer Protocol -- HTTP/1.1", RFC 2616, Section 10.2.2, 201 Created
  14. Fielding, et al., "Hypertext Transfer Protocol -- HTTP/1.1", RFC 2616, Section 10.2.5, 204 No Content
  15. Fielding, et al., "Hypertext Transfer Protocol -- HTTP/1.1", RFC 2616, Section 10.4.1, 400 Bad Request
  16. Fielding, et al., "Hypertext Transfer Protocol -- HTTP/1.1", RFC 2616, Section 10.4.2, 401 Authorization Required
  17. Fielding, et al., "Hypertext Transfer Protocol -- HTTP/1.1", RFC 2616, Section 10.4.5, 404 Not Found
  18. Fielding, et al., "Hypertext Transfer Protocol -- HTTP/1.1", RFC 2616, Section 10.4.7, 406 Not Acceptable
  19. Fielding, et al., "Hypertext Transfer Protocol -- HTTP/1.1", RFC 2616, Section 10.4.10, 409 Conflict
  20. Fielding, et al., "Hypertext Transfer Protocol -- HTTP/1.1", RFC 2616, Section 10.4.12, 411 Length Required
  21. Fielding, et al., "Hypertext Transfer Protocol -- HTTP/1.1", RFC 2616, Section 10.4.13, 412 Precondition Failed
  22. Fielding, et al., "Hypertext Transfer Protocol -- HTTP/1.1", RFC 2616, Section 10.4.16, 415 Unsupported Media Type
  23. Fielding, et al., "Hypertext Transfer Protocol -- HTTP/1.1", RFC 2616, Section 10.5.1, 500 Internal Server Error

Informative references