DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Installing and Debugging an Apereo Cas Application
  • The Trust Problem in Modern SaaS: Why Your Authentication Succeeded, and You Still Got Breached
  • Your API Authentication Isn’t Broken; It’s Quietly Failing in These 6 Ways
  • Context-Aware Authorization for AI Agents

Trending

  • AI Agents in Java: Architecting Intelligent Health Data Systems
  • What Is Plagiarism? How to Avoid It and Cite Sources
  • Alternative Structured Concurrency
  • The Documentation Crisis Nobody Sees: Why AI Agents Are Breaking Faster Than Humans Can Document Them
  1. DZone
  2. Software Design and Architecture
  3. Integration
  4. Apereo CAS: Step by Step Guide To Implement a Custom Authentication Handler

Apereo CAS: Step by Step Guide To Implement a Custom Authentication Handler

In this article, we are going to look into the details of implementing a custom authentication handler in an Apereo CAS application.

By 
Upul Kamburawala user avatar
Upul Kamburawala
·
Oct. 10, 21 · Tutorial
Likes (3)
Comment
Save
Tweet
Share
7.4K Views

Join the DZone community and get the full member experience.

Join For Free

As described in a previous article about getting an Apereo CAS application up and running, we used the default username and password to log in to the CAS. But in a real-world scenario, we need to implement some sort of mechanism to authenticate a user. It is more common to use an authentication handler for this purpose. In this article, we are going to look into the details of implementing a custom authentication handler in an Apereo CAS (hereafter it will be simply referred to as CAS) application.

Note: Additional implementational details are available inside the following code blocks as Java comments.

Following are steps for implementing a custom authentication handler:

  • Import the CAS overlay project into the eclipse IDE.
  • Before we start any coding, you need to make sure you have the following dependencies in your build.gradle file:
Java
 
dependencies {
	.....
    // Other CAS dependencies/modules may be listed here...
    compile"org.apereo.cas:cas-server-support-json-service-registry:${casServerVersion}"
    compile"org.apereo.cas:cas-server-core-authentication-api:${casServerVersion}"
    compile"org.apereo.cas:cas-server-core-web-api:${casServerVersion}"
    compile"org.apereo.cas:cas-server-core-util-api:${casServerVersion}"

}
  • The next step is to define the authentication handler class. The role of this class is to validate credentials and send back the result to the client. Create a package in the "src/main/java" folder and create a new class inside this package. This class should extend “AbstractUsernamePasswordAuthenticationHandler” available in the "org.apereo.cas.authentication.handler.support " package. The following code snippets should depict to you what a custom authentication handler looks like.

Java
 
Public class MyAuthHandler extends AbstractUsernamePasswordAuthenticationHandler{
	
  	/* If you want to make availble custom properties defined in 
  	 "cas.properties" file in to this class*/
    @Autowired
	private CasConfigurationProperties casProperties;
  
  	Public MyAuthHandler(String name, ServicesManager servicesManager, PrincipalFactory principalFactory, Integer order) {
            super(name, servicesManager, principalFactory, order);
    }

  	@Override
    Protected AuthenticationHandlerExecutionResult authenticateUsernamePasswordInternal(finalUsernamePasswordCredentialcredential,
        final String originalPassword) throws GeneralSecurityException {

    //If login failed throw an exception
    if (!isSuccesfulLogin())) {
        throw new FailedLoginException();
    }

    //If login is successful, then create and return back the resolved user //details. If there are additional parameter such as warning about the //password Can be passed inside the “ArrayList()” 
    AuthenticationHandlerExecutionResult principle = createHandlerResult(credential,
        this.getPrincipalFactory( ).createPrincipal( id, user), new ArrayList<>(0) );
        return principle;
    }
}
  • Next, we will look into how to implement the “authenticateUsernamePasswordInternal” method in detail. The following code snippets illustrate these details:
Java
 
@Override
protected AuthenticationHandlerExecutionResult  authenticateUsernamePasswordInternal(finalUsernamePasswordCredentialcredential,
	final String originalPassword) throwsGeneralSecurityException {

    //username and password can be extracted from the credential parameter
    String username = credential.getUsername();
    String password = credential.getPassword();

    //If there is any other additional parameter, if you want pass from the login 
    //page, then you can retrieve them in HTTP request object
    HttpServletRequest requestObj = ((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest();

    String otherparam = (String)requestObj.getParameter("otherparam");
	
  	//If you want to pass any properties to authenticator class, pass "casProperties" here 
  	MyAuthenticator authenticator = new MyAuthenticator(casProperties);
    
  	/*Authenticate the user credentials using some mechanism like 
    verifying them against the data available in a database */
    User userObj=authenticator.login(username, password);

    final Map<String,List<Object>> attributes= new HashMap<String,List<Object>>();
    final Map<String, Object>user = new HashMap<>();
    final List<Object> userInfo = new ArrayList<>();

    if (userObj != null && userObj.isSuccesfulLogin())) {

    	user.put("id", userObj.id());
            user.put("firstname", userObj.getFirstname());
            user.put("lastname",userObj.getSurname());
            user.put("username", userObj.getUsername());
            user.put("email", userObj.getEmail());
            user.put("roles", StringUtils.join(userObj.listRoles(), ","));

    }else{
    	throw new FailedLoginException();

    }

    userInfo.add(user);
    attributes.put("attributes", userInfo);

   /* In the last parameter, you can pass back set of warnings related to the credentials 
   and show them user if needed as ArrayList<> object. In this example we don't send any.
   */
    AuthenticationHandlerExecutionResult principal = createHandlerResult(credential,
    this.getPrincipalFactory().createPrincipal( id, attributes), new ArrayList<>(0) );

   // return back the resolved principal
    return principal;	

}
  • Once the handler class is ready, it needed to be registered with CAS. CAS is built on the Java Spring framework. Therefore this can be done through a configuration class. All we do in this class is create a bean of the MyAuthHandler class, which we create in the previous step, and register it as a CAS Authentication plan. Create another package inside the "src/main/java" folder and create a class in it. Following is how this configuration class looks:
Java
 
@Configuration("MyAuthenticationEventExecutionPlanConfiguration")
@EnableConfigurationProperties(CasConfigurationProperties.class)
Public class MyAuthenticationEventExecutionPlanConfiguration implements AuthenticationEventExecutionPlanConfigurer{

    @Autowired
    private CasConfigurationProperties casProperties;

  /*here in 4th parameter, we can set the order of this handler is executed by CAS,
      if there are multiple authentication stratagies are avaible */
    @Bean
    Public AuthenticationHandler myAuthHandler() {
    	final MyAuthHandler handler = new MyAuthHandler("authHandler", null,null ,1, casProperties);
	    return handler;
    }

    @Override
    Public void configureAuthenticationExecutionPlan(AuthenticationEventExecutionPlan plan) {
            plan.registerAuthenticationHandler(myAuthHandler());
    }	
	
}
  • As the final step, we need to make sure our handler is available to the CAS. For this, create the “META-INF” folder inside the "src\main\resources" folder of your project. Add a file with the name “spring.factories” inside the above-created folder. Add the following line to that file:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.myorg.config.AuthenticationEventExecutionPlanConfigurer

  • Now go to the root folder of the project in the command prompt and give the command to start the server. On the startup console, there should be a log message you can see our handle is binding to CAS runtime.

Now if you are going to log in through the login page, our authentication handler will be executed and our custom authentication will be used. In another article, we are going to see how to customize the user interface of the CAS application.

Central Authentication Service authentication

Opinions expressed by DZone contributors are their own.

Related

  • Installing and Debugging an Apereo Cas Application
  • The Trust Problem in Modern SaaS: Why Your Authentication Succeeded, and You Still Got Breached
  • Your API Authentication Isn’t Broken; It’s Quietly Failing in These 6 Ways
  • Context-Aware Authorization for AI Agents

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook