This document describes how to customize this authorization server implementation.
This authorization server implementation uses Authlete as its backend. What this means are (1) that the core part of the implementation of OAuth 2.0 and OpenID Connect is not in the source tree of spring-oauth-server but in the Authlete server on cloud, and (2) that authorization data such as access tokens, settings of the authorization server itself and settings of client applications are not stored in any local database but in the database on cloud. Therefore, to put it very simply, this implementation is just an intermediary between client applications and Authlete server as illustrated below.
+--------+ +---------------------+ +----------+
| | | | | |
| Client | <------> | spring-oauth-server | <------> | Authlete |
| | | | | |
+--------+ +---------------------+ +----------+
However, because Authlete focuses on authorization and does NOT do anything about end-user authentication, functions related to authentication are implemented in the source tree of spring-oauth-server.
Therefore, at least, you must customize parts related to end-user authentication. On the other hand, customization of other parts such as UI design of the authorization page is optional.
Authlete provides Web APIs that can be used to write an authorization server. authlete-java-common is a library which directly communicates with the Web APIs, and authlete-java-jaxrs is a library which provides utility classes wrapping the authlete-java-common API to make it much easier for developers to implement an authorization server than using authlete-java-common API directly. spring-oauth-server is written using Spring Framework and authlete-java-jaxrs API exposed by the utility classes.
As its name implies, authlete-java-jaxrs library depends on JAX-RS 2.0 API. JAX-RS means The Java API for RESTful Web Services. JAX-RS 2.0 API has been standardized by JSR 339 and it is included in Java EE 7.
The figure below illustrates the relationship among the components mentioned so far.
+----------------------------------------+
| spring-oauth-server |
+--------+----+--------------------------+
| | | authlete-java-jaxrs |
| Spring | +---+----------------------+ +----------+
| | JAX-RS | authlete-java-common | <------> | Authlete |
+--------+-------------------------------+ +----------+
The implementation of the authorization endpoint is in
AuthorizationEndpoint.java
. The code is incredibly short
although it supports OpenID Connect in addition to OAuth 2.0. There is little
need to change this file.
The implementation uses AuthorizationRequestHandler
class
and delegates the task to handle an authorization request to handle()
method
of the class. Details about the class is written in the README file of
authlete-java-jaxrs library. What is important here is that the
constructor of the class requires an implementation of
AuthorizationRequestHandlerSpi
interface and that the
implementation must be provided by you. In other words, the methods in
AuthorizationRequestHandlerSpi
interface are customization points.
The interface has the methods listed below. See the JavaDoc of authlete-java-jaxrs API for details about the requirements of these methods.
boolean isUserAuthenticated()
long getUserAuthenticatedAt()
String getUserSubject()
String getAcr()
Response generateAuthorizationPage(AuthorizationResponse)
The most important method among the above is
generateAuthorizationPage()
. The method is called to
generate an authorization page. In contrast, the other methods are not so
important because they are called only when an authorization request comes
with a special request parameter prompt=none
. If you have no mind to
support prompt=none
, you can leave your implementations of the methods
empty. Details about prompt=none
is written in
"3.1.2.1. Authorization Request" of OpenID Connect Core 1.0.
The implementation of AuthorizationRequestHandlerSpi
interface in
spring-oauth-server is written in
AuthorizationRequestHandlerSpiImpl.java
. The implementation
class in the file, AuthorizationRequestHandlerSpiImpl
, extends
AuthorizationRequestHandlerSpiAdapter
class which is an
empty implementation of AuthorizationRequestHandlerSpi
interface, and
overrides generateAuthorizationPage()
method only. The code snippet below
shows the rough structure of the implementation.
class AuthorizationRequestHandlerSpiImpl extends AuthorizationRequestHandlerSpiAdapter
{
......
@Override
public Response generateAuthorizationPage(AuthorizationResponse info)
{
......
}
}
As mentioned, generateAuthorizationPage()
in AuthorizationRequestHandlerSpi
interface is a method to generate an authorization page. The current
implementation of the method in spring-oauth-server retrieves data from the
argument (an intance of AuthorizationResponse
class which
represents a response from Authlete's /api/auth/authorization
API) and
embeds them into an HTML template, authorization.ftl
.
To achieve this, the implementation uses Viewable
class.
If you want to customize the authorization page, change the implementation
of generateAuthorizationPage()
method and/or the template of the
authorization page (authorization.ftl
). See the JavaDoc of
authlete-java-common library for details about AtuhorizationResponse
class.
For the internationalization of the authorization page, you may take
ui_locales
parameter into consideration which may be contained in an
authorization request. It is a new request parameter defined in OpenID
Connect Core 1.0. The following is the description about the parameter
excerpted from the specification.
OPTIONAL. End-User's preferred languages and scripts for the user interface, represented as a space-separated list of BCP47 [RFC5646] language tag values, ordered by preference. For instance, the value "fr-CA fr en" represents a preference for French as spoken in Canada, then French (without a region designation), followed by English (without a region designation). An error SHOULD NOT result if some or all of the requested locales are not supported by the OpenID Provider.
You can get the value of ui_locales
request paremeter as a String
array
by calling getUiLocales()
method of AuthorizationResponse
instance. Note
that, however, you have to explicitly specify which UI locales to support
using the management console (Service Owner Console) because
getUiLocales()
method returns only supported UI locales. In other words,
it is ensured that the array returned by getUiLocales()
never contains
unsupported UI locales whatever ui_locales
request parameter contains.
It is up to you whether to honor ui_locales
parameter or not. Of course,
you may use any means you like to internationalize the authorization page.
An authorization request may contain display
request parameter to specify
how to display the authorization page. It is a new request parameter defined
in OpenID Connect Core 1.0. The predefined values of the request
parameter are as follows. The descriptions in the table are excerpts from
the specification.
Value | Description |
---|---|
page | The Authorization Server SHOULD display the authentication and consent UI consistent with a full User Agent page view. If the display parameter is not specified, this is the default display mode. |
popup | The Authorization Server SHOULD display the authentication and consent UI consistent with a popup User Agent window. The popup User Agent window should be of an appropriate size for a login-focused dialog and should not obscure the entire window that it is popping up over. |
touch | The Authorization Server SHOULD display the authentication and consent UI consistent with a device that leverages a touch interface. |
wap | The Authorization Server SHOULD display the authentication and consent UI consistent with a "feature phone" type display. |
You can get the value of display
request parameter as an instance of
Display
enum by calling getDisplay()
method of
AuthorizationResponse
instance. By default, all the display types are
checked as supported in the management console (Service Owner Console),
but you can uncheck them to declare some values are not supported. If an
unsupported value is specified as the value of display
request parameter,
it will result in returning an invalid_request
error to the client
application that made the authorization request.
In an authorization page, an end-user decides either to grant permissions to the client application which made the authorization request or to deny the authorization request. An authorization server must be able to receive the decision and return a proper response to the client application according to the decision.
The current implementation of spring-oauth-server receives the end-user's
decision at /api/authorization/decision
. In this document, we call the
endpoint authorization decision endpoint. In spring-oauth-server, the
implementation of the authorization decision endpoint is in
AuthorizationDecisionEndpoint.java
.
The implementation uses AuthorizationDecisionHandler
class
and delegates the task to handle an end-user's decision to handle()
method
of the class. Details about the class is written in the README file of
authlete-java-jaxrs library. What is important here is that the
constructor of the class requires an implementation of
AuthorizationDecisionHandlerSpi
interface and that the
implementation must be provided by you. In other words, the methods in
AuthorizationDecisionHandlerSpi
interface are customization points.
The interface has the methods listed below. See the JavaDoc of authlete-java-jaxrs API for details about the requirements of these methods.
boolean isClientAuthorized()
long getUserAuthenticatedAt()
String getUserSubject()
String getAcr()
getUserClaim(String claimName, String languageTag)
The implementation of AuthorizationDecisionHandlerSpi
interface in
spring-oauth-server is written in
AuthorizationDecisionHandlerSpiImpl.java
. The implementation
class in the file, AuthorizationDecisionHandlerSpiImpl
, extends
AuthorizationDecisionHandlerSpiAdapter
class which is an
empty implementation of AuthorizationDecisionHandlerSpi
interface, and
overrides all the methods except getAcr()
. The code snippet below shows
the rough structure of the implementation.
class AuthorizationDecisionHandlerSpiImpl extends AuthorizationDecisionHandlerSpiAdapter
{
......
@Override
public boolean isClientAuthorized()
{
......
}
@Override
public long getUserAuthenticatedAt()
{
......
}
@Override
public String getUserSubject()
{
......
}
@Override
public Object getUserClaim(String claimName, String languageTag)
{
......
}
}
Authlete does not care about how to authenticate an end-user at all. Instead, Authlete requires the subject of the authenticated end-user.
Subject is a technical term in the area related to identity and it means a unique identifier. In a typical case, subjects of end-users are values of the primary key column or another unique column in a user database.
When an end-user grants permissions to a client application, you have
to let Authlete know the subject of the end-user. In the context of
AuthorizationDecisionHandlerSpi
interface, this can be described as
follows: "if isClientAuthorized()
returns true
, then getUserSubject()
must return the subject of the end-user."
For end-user authentication, spring-oauth-server has UserDao
class and
UserEntity
class. These two classes compose a dummy user database.
Of course, you have to replace them with your own implementation to
refer to your actual user database.
The implementation of the token endpoint is in TokenEndpoint.java
.
The code is incredibly short and there is little need to change the content of
the file.
The implementation uses TokenRequestHandler
class and delegates
the task to handle a token request to handle()
method of the class. Details about
the class is written in the README file of authlete-java-jaxrs library. What
is important here is that the constructor of the class requires an implementation
of TokenRequestHandlerSpi
interface and that the implementation
must be provided by you. In other words, the methods in TokenRequestHandlerSpi
interface are customization points.
The current definition of the interface has only one method named authenticateUser
.
This method is used to authenticate an end-user. However, the method is called
only when the grant type of a token request is Resource Owner Password
Credentials. Therefore, if you have no mind to support the grant type,
you can leave your implementation of the method empty.
The implementation of TokenRequestHandlerSpi
interface in spring-oauth-server
is written in TokenRequestHandlerSpiImpl.java
. The implmentation
class in the file, TokenRequestHandlerSpiImpl
, extends
TokenRequestHandlerSpiAdapter
class which is an empty
implementation of TokenRequestHandlerSpi
interface, and overrides
authenticateUser()
method. The code snippet below shows the rough structure of
the implementation.
class TokenRequestHandlerSpiImpl extends TokenRequestHandlerSpiAdapter
{
......
@Override
public String authenticateUser(String username, String password)
{
......
}
}
The implementation of the introspection endpoint is in
IntrospectionEndpoint.java
.
RFC 7662 (OAuth 2.0 Token Introspection) requires that the endpoint
be protected in some way or other. The implementation of the protection in
IntrospectionEndpoint.java
is for demonstration purpose only,
and it is not suitable for commercial use. Therefore, modify the code
accordingly.
- Authlete - Authlete Home Page
- authlete-java-common - Authlete Common Library for Java
- authlete-java-common API - JavaDoc of Authlete Common Library for Java
- authlete-java-jaxrs - Authlete Library for JAX-RS (Java)
- authlete-java-jaxrs API - JavaDoc of Authlete Library for JAX-RS (Java)
Purpose | Email Address |
---|---|
General | [email protected] |
Sales | [email protected] |
PR | [email protected] |
Technical | [email protected] |