Client (RP) examples

This section contains client (RP) configuration examples to illustrate options for implementing InAcademia in some commonly available software libraries.

Important note: the following code samples cannot be used in a live production environment, and are only intended to illustrate the basic steps required to complete a transaction with the InAcademia service. Additional measures must be implemented by the Merchant in order to ensure a secure and fit-for-purpose implementation.

Before you can start, you need to register your service at InAcademia. You will receive an “ClientID” and you must provide a RedirectURI where the response for your service will be returned. Note that you cannot change this endpoint without re-registering. InAcademia will ask you to prove ownership of the domain used in the RedirectURI. More information on registration can be found here: https://inacademia.org/registering-your-service/

InAcademia is an OIDC-compliant OP. Therefore, all certified OIDC RPs should be compatible with InAcademia. A list of certified products and libraries can be found at the OpenID Connect website: http://openid.net/developers/certified/

 

Apache: mod_auth_openidc

More information can be found here.

The OIDC module for Apache is a very straight forward way of setting up Affiliation validation with InAcademia which can be integrated with many applications. This example assumes a script would live inside a specific directory on your server, protected by the OIDC module. If InAcademia validation is successful the script would pick this up, set the remote user parameter and then continue to a point in the application of your specification.

Installing mod_auth_oidc

Based on https://github.com/pingidentity/mod_auth_openidc For most common linux distributions, the implementation would pull the latest and greatest from the github release page at: https://github.com/pingidentity/mod_auth_openidc/releases. For debian/ubuntu, historically, this Apache module has been part of the standard repositories, and the implementation would install this module alternatively using: sudo apt install libapache2-mod-auth-openidc. The appropriate https/ssl configuration should be made relevant to the merchant’s domain.

Configuring mod_auth_oidc for InAcademia The mod would be configured to work with InAcademia by providing relevant configuration data to the module inside the VirtualHost configuration of the relevant server.

For a secure configuration, you must set an appropriate value for CryptoPassphrase, which would be used as part of the session and cookie hash. A long random string, for example generated using tr -c -d ‘0123456789abcdefghijklmnopqrstuvwxyz’ </dev/urandom | dd bs=32 count=1 2>/dev/null;echo, would be appropriate.

Example for configuration for illustration purposes

Listen <port>
ServerName <server name>

LoadModule auth_openidc_module /usr/lib/apache2/modules/mod_auth_openidc.so
LoadModule ssl_module /usr/lib/apache2/modules/mod_ssl.so

<VirtualHost _default_:*>
    OIDCProviderMetadataURL <inacademia url>/.well-known/openid-configuration
    OIDCClientID <client id>
    OIDCRedirectURI https://<hostname>:<port>/your_redirect_page
    OIDCResponseType id_token
    OIDCScope "openid student"
    OIDCAuthRequestParams "claims=%7B%22id_token%22%3A%20%7B%22domain%22%3A%20null%7D%7D"

    OIDCCryptoPassphrase <secret>

    <Location /protected>
      AuthType openid-connect
      Require valid-user
    </Location>

    SSLEngine on
    SSLCertificateFile <ssl cert>
    SSLCertificateKeyFile <ssl key>
</VirtualHost>

Secure location To trigger Affiliation validation, it would be necessary to create a Location directive in your virtualhost section as illustrated in the example below.

<Location /validate/>
AuthType openid-connect
Require valid-user
LogLevel debug
</Location>

It would be necessary to make sure the directory is part of the Redirect URL!

Python 3: pyoidc

More information can be found here.

Example configuration for illustration purposes

Setup client instance

from oic.oic import Client
from oic.oic.message import RegistrationResponse
from oic.utils.authn.client import CLIENT_AUTHN_METHOD

# create a client instance
client = Client(client_id=..., client_authn_method=CLIENT_AUTHN_METHOD)

# fetch the provider configuration information
client.provider_config(inacademia_url)

Make authentication request

from oic.oauth2 import rndstr
from oic.oic.message import Claims, ClaimsRequest
from oic.utils.http_util import Redirect


# make the authentication request
scope = "openid student" # request verification of student affiliation
claims_request = ClaimsRequest(id_token=Claims(domain=None)) # request the additional claim 'domain'
args = {
    "client_id": client.client_id,
    "response_type": "id_token",
    "redirect_uri": redirect_uri,
    "nonce": rndstr(),
    "scope": scope,
    "claims": claims_request
}
auth_req = client.construct_AuthorizationRequest(request_args=args)
login_url = auth_req.request(client.authorization_endpoint)
http_response = Redirect(login_url)

Receive the authentication response

from oic.utils.http_util import Response

# Send HTML page with form that POSTs the url fragment back to the server
page = """
<html><body>
<form action="/parse_response" method="post">
<input type="hidden" name="response" id="response" value=""/>
</form>
<script type="text/javascript">
document.getElementById("response").value = window.location.hash.substring(1);
document.forms[0].submit();
</script>
</body></html>
"""
http_response = Response(page)

Process the authentication response server-side

from oic.oic.message import AuthorizationResponse
from urllib.parse import unquote, parse_qsl

post_data = ... # read POST data from HTTP request
params = dict(parse_qsl(unquote(post_data)))["response"]
authn_resp = client.parse_response(AuthorizationResponse, params, sformat="urlencoded")
id_token = authn_resp["id_token"]

# ... Verify the ID Token and use its claims

Java: Nimbus OAuth 2.0 SDK

More information can be found here.

Example configuration for illustration purposes

Fetch provider configuration information

import java.io.InputStream;
import java.net.URI;
import java.net.URL;

import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;

URI issuerURI = new URI(inacademiaURL);
URL providerConfigurationURL = issuerURI.resolve(
        "/.well-known/openid-configuration").toURL();
InputStream stream = providerConfigurationURL.openStream();
// Read all data from URL
String providerInfo = null;
try (java.util.Scanner s = new java.util.Scanner(stream)) {
    providerInfo = s.useDelimiter("\\A").hasNext() ? s.next() : "";
}
OIDCProviderMetadata providerMetadata = OIDCProviderMetadata
        .parse(providerInfo);

Make authentication request

import java.net.URI;

import com.nimbusds.oauth2.sdk.ResponseType;
import com.nimbusds.oauth2.sdk.Scope;
import com.nimbusds.openid.connect.sdk.AuthenticationRequest;
import com.nimbusds.openid.connect.sdk.ClaimsRequest;
import com.nimbusds.openid.connect.sdk.Nonce;
import com.nimbusds.openid.connect.sdk.OIDCResponseTypeValue;

Scope studentValidationScope = new Scope("openid", "student");


AuthenticationRequest.Builder authenticationRequest = new AuthenticationRequest.Builder(
        new ResponseType(OIDCResponseTypeValue.ID_TOKEN),
        studentValidationScope, clientID, redirectURI);

// Request additional claim 'domain'
ClaimsRequest claimsReq = new ClaimsRequest();
claimsReq.addIDTokenClaim("domain");

authenticationRequest.nonce(new Nonce()).claims(claimsReq)
        .endpointURI(providerMetadata.getAuthorizationEndpointURI());

URI loginURL = authenticationRequest.build().toURI();

// ... Make HTTP Redirect to loginURL

Receive the authentication response

StringBuilder sb = new StringBuilder();
sb.append("<html><body>");
sb.append("<form action=\"/response\" method=\"post\">");
sb.append("<input type=\"hidden\" name=\"response\" id=\"response\" value=\"\"/>");
sb.append("</form>");
sb.append("<script type=\"text/javascript\">");
sb.append("document.getElementById(\"response\").value = window.location.hash.substring(1);");
sb.append("document.forms[0].submit();");
sb.append("</script>");
sb.append("</body></html>");

// ... Make HTTP response with sb.toString()

Process the authentication response server-side

import java.net.URI;

import com.nimbusds.jwt.JWT;
import com.nimbusds.jwt.ReadOnlyJWTClaimsSet;
import com.nimbusds.openid.connect.sdk.AuthenticationResponseParser;
import com.nimbusds.openid.connect.sdk.AuthenticationSuccessResponse;

Map<String, String> post_data = ... // read POST data from HTTP request

URI url = new URI("http://example.com#" + post_data.get("response"));
AuthenticationResponse authResp = AuthenticationResponseParser.parse(url);
AuthenticationSuccessResponse successResponse = (AuthenticationSuccessResponse) authResp;

JWT idToken = successResponse.getIDToken();

// ... Verify the ID Token and use its claims