Basic Authentication for REST Services

Version: 17.07

Supported Since: 17.07

Use Case Description

The REST service described under REST Service Mediation has to be secured by allowing access only to properly authenticated users. Unauthenticated requests to access the API should be declined with HTTP 401 responses with appropriate error messages.

Proposed Solution

HTTP basic authentication is utilized for the access control mechanism, where the user sends a Basic Authorization header with a base 64 encoded, colon-separated username-password pair as part of the API access request. UltraESB reads credentials from a CSV-formatted user credentials file, and decodes and validates passwords received on the Authorization headers against their respective usernames. If either the header cannot be parsed or it does not correspond to a valid username-password pair, UltraESB blocks the request and returns an HTTP 401 response along with an appropriate error message. Otherwise the request is allowed to proceed as in the case of the original REST service mediation flow.

Implementation

Prerequisites

  1. Complete the REST Service Mediation introductory sample, on which we will base our new solution.

  2. Obtain a copy of the above sample project.

  3. Remove the .idea and <project-name>.iml file in the root directory, so that UltraStudio would not recognize the new copy as the old project.

  4. Modify the artifactId in pom.xml, and projectId and projectName in project.xpml, to new values.

  5. Open the pom.xml file of the new copy via UltraStudio’s Open option, and select the Open as Project option when prompted, to import the entire project as a new Ultra project.

Alternatively you can:

  1. create a new sample project, selecting the REST Service Mediation sample from the UltraStudio sample repository, or

  2. redo the REST Service Mediation sample from scratch, and resume from there.

Defining Credentials

Before we add a HTTP (Basic) authenticator to our flow, we have to define a User Detail Service that provides user information for the authentication flow. Define the following resource under project.xpml:

<x:resource id="userDetail">
    <bean class="org.springframework.security.provisioning.InMemoryUserDetailsManager" id="userDetail">
        <constructor-arg name="users">
            <list>
                <bean class="org.springframework.security.core.userdetails.User">
                    <constructor-arg name="username" value="admin"/>
                    <constructor-arg name="password" value="password"/>
                    <constructor-arg name="authorities">
                        <list>
                            <bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
                                <constructor-arg name="role" value="ROLE_ADMIN"/>
                            </bean>
                            <bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
                                <constructor-arg name="role" value="ROLE_USER"/>
                            </bean>
                        </list>
                    </constructor-arg>
                </bean>
            </list>
        </constructor-arg>
    </bean>
</x:resource>

The above example is a simple in-memory user detail manager, but it can be more sophisticated and customizable (e.g. one based on JDBC (database-backed) or LDAP) in real scenarios.

We also need to define an Authentication Manager that utilizes the above userDetail resource:

<x:resource id="config">
    <bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
        <constructor-arg name="providers">
            <list>
                <bean class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
                    <property name="userDetailsService" ref="userDetail"/>
                </bean>
            </list>
        </constructor-arg>
    </bean>
</x:resource>

Adding the Basic Authenticator to the REST service flow

The HTTP Authenticator processing element is bundled with the HTTP NIO connector, so you do not need to specifically add it as a project dependency as long as you already have a HTTP connector in your flow.

  1. Add a HTTP authenticator (under Processors → HTTP on the palette) to the flow.

  2. Configure the HTTP authenticator as follows:

    HTTP Authentication Scheme

    Basic

    Realm Name

    adroitlogic

    User Detail Service

    userDetail

    Authentication Manager

    config

  3. Rewire the flow such that, before hitting the HTTP sender, the message flows through the HTTP authenticator:

    1. Delete the path going out from the NIO HTTP listener’s Processor port.

    2. Connect the above port to the Input port of HTTP authenticator.

    3. Connect the Next port of the HTTP authenticator to the Input port of the NIO HTTP sender.

    4. Connect the On Exception port of HTTP authenticator to the Input (bottommost) port of the NIO HTTP listener (so that it now has 2 incoming connection paths).

The completed flow would resemble the following:

basic auth flow

Now run the previously created RESTProxy configuration (or create a new one, if you are on a new project) to get the ESB running.

Testing

  1. Send a HTTP GET request to http://localhost:8280/service/rest-proxy?q=London&APPID=4f39ab00e0ea663ad801b6bd12799cb6 (similar to how you tested the REST Service Mediation sample). However, since we are not yet sending any credentials, you should receive an "unauthorized" error response:

    HTTP/1.1 401 Unauthorized
    WWW-Authenticate: Basic realm="adroitlogic"
    ...
    Content-Length: 0
    Connection: close
  2. Now try another request with the admin:password credential pair (as configured in the user detail service). (You can use the Http Authentication option under Authentication tab of the Toolbox HTTP/S client for this.) You should receive a successful response from the OpenWeatherMap API, since the authenticator lets the request through:

    HTTP/1.1 200 OK
    Cache-Control: no-cache, must-revalidate
    ...
    Content-Length: 446
    Connection: close
    
    {"coord":{"lon":-83.45,"lat":39.89},...
  3. Finally, try another request with an invalid credential pair (one that is not configured in the user detail service). You should receive an error response, but with a "bad credentials" message instead of the former "unauthorized" message:

    HTTP/1.1 401 Bad credentials
    WWW-Authenticate: Basic realm="adroitlogic"
    ...
    Content-Length: 0
    Connection: close
In this topic
In this topic
Contact Us