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/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