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
Solved! Go to Solution.
Views
Replies
Total Likes
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
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
Views
Likes
Replies
Views
Likes
Replies