Expand my Community achievements bar.

Join expert-led, customer-led sessions on Adobe Experience Manager Assets on August 20th at our Skill Exchange.
SOLVED

AEMaaCS – User’s list based on Last Login Date

Avatar

Level 7

Hi, As we know, the lastLogin attribute is not natively provided by AEM in any version. For the AEM on-premise environments, we were able to capture this information by implementing an AuthenticationInfoPostProcessor or by tracking the user token expiry.

However, with AEM as a Cloud Service (AEMaaCS), these approaches don’t appear to be technically feasible due to platform restrictions.

Could you please share your expert insights on how we can achieve similar functionality in AEMaaCS? Any recommended best practices or workarounds would be greatly appreciated

Regards
Brijesh Yadav

1 Accepted Solution

Avatar

Correct answer by
Level 4

Hi Brijesh,


One approach could be creating custom handler, below is skeleton version(used for our app) and you can add respective code in @Override methods

PS: Below class denotes Okta specific platform that can get interchanged according your desired platform

package com.example.aem.auth;

import org.apache.sling.auth.core.spi.AuthenticationHandler;
import org.apache.sling.auth.core.spi.AuthenticationInfo;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;

import javax.servlet.Servlet;
import javax.servlet.ServletException;
import java.io.IOException;
import java.util.Map;

@Component(service = Servlet.class, property = {
    Constants.SERVICE_DESCRIPTION + "=Okta Authentication Handler",
    "sling.servlet.methods=GET",
    "sling.servlet.paths=/bin/okta-auth"
})
public class OktaAuthenticationHandler extends SlingSafeMethodsServlet implements AuthenticationHandler {

    @reference
    private OktaService oktaService;

    @Override
    protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
        String code = request.getParameter("codexxx");
        if (code != null) {
            String accessToken = oktaService.exchangeCodeForToken(code);
            Map<String, Object> userProfile = oktaService.getUserProfile(accessToken);
            String userId = (String) userProfile.get("subServiceUser");

            // Create or authenticate the user in AEM
            authenticateUser(userId);

            // Log the login event
            logLoginEvent(userId);

            // Proceed with the request
            response.getWriter().write("Authentication successful");
        } else {
            // Redirect to Okta for authentication
            String authorizationUrl = oktaService.getAuthorizationUrl();
            response.sendRedirect(authorizationUrl);
        }
    }

    private void authenticateUser(String userId) {
        // Implement user authentication logic here
    }

    private void logLoginEvent(String userId) {
        // Implement login event logging logic here
    }

    @Override
    public AuthenticationInfo extractCredentials(HttpServletRequest request, HttpServletResponse response) {
        // Implement credential extraction logic here
        return null;
    }

    @Override
    public boolean requestCredentials(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // Implement credential request logic here
        return false;
    }

    @Override
    public void dropCredentials(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // Implement credential drop logic here
    }

    @Override
    public boolean authenticationSucceeded(HttpServletRequest request, HttpServletResponse response, AuthenticationInfo authInfo) {
        // Implement authentication success logic here
        return true;
    }

    @Override
    public void authenticationFailed(HttpServletRequest request, HttpServletResponse response, AuthenticationInfo authInfo) {
        // Implement authentication failure logic here
    }
}

  

Thanks

 

Kind regards,

Kiran Buthpur

View solution in original post

1 Reply

Avatar

Correct answer by
Level 4

Hi Brijesh,


One approach could be creating custom handler, below is skeleton version(used for our app) and you can add respective code in @Override methods

PS: Below class denotes Okta specific platform that can get interchanged according your desired platform

package com.example.aem.auth;

import org.apache.sling.auth.core.spi.AuthenticationHandler;
import org.apache.sling.auth.core.spi.AuthenticationInfo;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;

import javax.servlet.Servlet;
import javax.servlet.ServletException;
import java.io.IOException;
import java.util.Map;

@Component(service = Servlet.class, property = {
    Constants.SERVICE_DESCRIPTION + "=Okta Authentication Handler",
    "sling.servlet.methods=GET",
    "sling.servlet.paths=/bin/okta-auth"
})
public class OktaAuthenticationHandler extends SlingSafeMethodsServlet implements AuthenticationHandler {

    @reference
    private OktaService oktaService;

    @Override
    protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
        String code = request.getParameter("codexxx");
        if (code != null) {
            String accessToken = oktaService.exchangeCodeForToken(code);
            Map<String, Object> userProfile = oktaService.getUserProfile(accessToken);
            String userId = (String) userProfile.get("subServiceUser");

            // Create or authenticate the user in AEM
            authenticateUser(userId);

            // Log the login event
            logLoginEvent(userId);

            // Proceed with the request
            response.getWriter().write("Authentication successful");
        } else {
            // Redirect to Okta for authentication
            String authorizationUrl = oktaService.getAuthorizationUrl();
            response.sendRedirect(authorizationUrl);
        }
    }

    private void authenticateUser(String userId) {
        // Implement user authentication logic here
    }

    private void logLoginEvent(String userId) {
        // Implement login event logging logic here
    }

    @Override
    public AuthenticationInfo extractCredentials(HttpServletRequest request, HttpServletResponse response) {
        // Implement credential extraction logic here
        return null;
    }

    @Override
    public boolean requestCredentials(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // Implement credential request logic here
        return false;
    }

    @Override
    public void dropCredentials(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // Implement credential drop logic here
    }

    @Override
    public boolean authenticationSucceeded(HttpServletRequest request, HttpServletResponse response, AuthenticationInfo authInfo) {
        // Implement authentication success logic here
        return true;
    }

    @Override
    public void authenticationFailed(HttpServletRequest request, HttpServletResponse response, AuthenticationInfo authInfo) {
        // Implement authentication failure logic here
    }
}

  

Thanks

 

Kind regards,

Kiran Buthpur