Configure Apereo CAS to submit authentication requests to a remote REST endpoint. Nothing to do with the native CAS REST API.
Within this short post I will provide several details to configure Apereo CAS to submit authentication requests to a remote REST endpoint. It has nothing to do with the native CAS REST API.
More highlights will be given about the response that has to be returned by the REST endpoint. For this purpose the open source identity manager Apache Syncope will be used to provide a sample endpoint returning verification results including principal id and principal attributes.
As reported into the relative section of the Apereo CAS guide, REST authentication is enabled by including the following dependencies in the WAR overlay:
<dependency>
<groupId>org.apereo.cas</groupId>
<artifactId>cas-server-support-rest-authentication</artifactId>
<version>${cas.version}</version>
</dependency>
This allows the CAS server to reach to a remote REST endpoint via a POST for verification of credentials. Credentials are passed via an Authorization header whose value is Basic XYZ where XYZ is a Base64 encoded version of the credentials. The response that is returned must be accompanied by a 200 status code where the JSON body should contain id and attributes fields, the latter being optional, which represent the authenticated principal for CAS. Attributes have to be returned as a JSON representation of a Map<String, Object>.
Now Apache Syncope has to be extended in order to provide a specific REST endpoint for our aims.
First of all we can implement the the transfer object to be used to return the principal.
See below an example.
package net.tirasa.samples;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class LoginResponseTO {
private String id;
private final Map<String, Object> attributes;
public LoginResponseTO() {
attributes = new HashMap<String, Object>();
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Map<String, Object> getAttributes() {
return attributes;
}
}
This class can be added into the Syncope overlay project, under the following path
syncope/common/src/main/java/net/tirasa/samples/
The next one is about the creation of the real REST endpoint.
First of all let’s define the REST service by providing the following class under the path
syncope/core/src/main/java/org/apache/syncope/core/services
package org.apache.syncope.core.services;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
import org.apache.syncope.common.services.JAXRSService;
@Path("tirasa/self")
public interface TirasaUserService extends JAXRSService {
@POST
@Path("login")
Response login();
}
An then, maybe in the same path, the following implementation
package org.apache.syncope.core.services;
import java.util.List;
import javax.ws.rs.core.Response;
import org.apache.syncope.common.to.UserTO;
import org.apache.syncope.core.rest.controller.UserController;
import org.springframework.beans.factory.annotation.Autowired;
import net.tirasa.samples.LoginResponseTO;
@Service public class TirasaUserServiceImpl extends AbstractServiceImpl implements TirasaUserService {
@Autowired
private UserController userController;
@Override
public Response login() {
UserTO userTO = userController.readSelf();
return Response.status(200).entity(createLoginResponseTO(userTO)).build();
}
private LoginResponseTO createLoginResponseTO(UserTO userTO) {
LoginResponseTO loginResponseTO = new LoginResponseTO();
loginResponseTO.setId(userTO.getUsername());
// add further custom attributes
loginResponseTO.getAttributes().put("attr1", "XXX");
loginResponseTO.getAttributes().put("attr2", "YYY");
// return the authenticated principal
return loginResponseTO;
}
}
Compile and deploy (or start it in embedded mode) your Syncope overlay and create your sample user.
Let’s come back to the CAS …
The following settings have to be added into "cas.properties" file in order to enable REST authentication against Apache Syncope specific endpoint:
cas.authn.rest.uri=http://<syncope host>.<domain>:<port>/syncope/rest/tirasa/self
cas.authn.rest.passwordEncoder.type=NONE
The configuration is almost completed here. By the way, in order to be able to retrieve returning principal attributes a further step is required: configure attributeReleasePolicy for your protected service. See the example below and pay attention to allowedAttributes parameter into attributeReleasePolicy section.
{
"@class": "org.apereo.cas.services.RegexRegisteredService",
"serviceId": "^http://saples.tirasa.net:808./.*",
"name": "tirasa",
"id": 3,
"description": "Allows tirasa services",
"evaluationOrder": 1,
"usernameAttributeProvider": {
"@class": "org.apereo.cas.services.PrincipalAttributeRegisteredServiceUsernameProvider",
"usernameAttribute": "id"
},
"logoutType": "BACK_CHANNEL",
"attributeReleasePolicy": {
"@class": "org.apereo.cas.services.ReturnAllowedAttributeReleasePolicy",
"authorizedToReleaseCredentialPassword": false,
"authorizedToReleaseProxyGrantingTicket": false,
"allowedAttributes": ["java.util.ArrayList", ["id", "attr1", "attr2"]]
},
"accessStrategy": {
"@class": "org.apereo.cas.services.DefaultRegisteredServiceAccessStrategy",
"enabled": true,
"ssoEnabled": true,
"caseInsensitive": true
}
}
Redeploy your CAS instance and enjoy your solution.