import javax.jcr.RepositoryException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.auth.core.spi.AuthenticationHandler;
import org.apache.sling.auth.core.spi.AuthenticationInfo;
import org.apache.sling.auth.core.spi.DefaultAuthenticationFeedbackHandler;
import org.apache.sling.jcr.api.SlingRepository;
import org.apache.sling.settings.SlingSettingsService;
import org.osgi.framework.ServiceRegistration;
import org.osgi.framework.Constants;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.day.crx.security.token.TokenCookie;
import com.day.crx.security.token.TokenUtil;
@Component(metatype = true, immediate = true, label = "SAS Authentication Handler", description = "Custom Authentication handler for SAS")
@Service
@Properties({
@Property(name = AuthenticationHandler.PATH_PROPERTY, value = {
"/content"
}),
@Property(name = Constants.SERVICE_RANKING, intValue = 10000),
@Property(name = Constants.SERVICE_DESCRIPTION, value = "SAS Authentication Handler")
})
public class SASAuthnHandler extends DefaultAuthenticationFeedbackHandler
implements AuthenticationHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(SASAuthnHandler.class);
private static final String REPO_DESC_ID = "crx.repository.systemid";
private static final String REPO_DESC_CLUSTER_ID = "crx.cluster.id";
// Standard params expected to support OotB login mechanism
private static final String REQUEST_METHOD = "POST";
private static final String USERNAME = "j_username";
private static final String PASSWORD = "j_password";
private static final String REQUEST_URL_SUFFIX = "/j_security_check";
// Custom params expected to support extra features
private static final String KEEP_ME_LOGGED_IN = "keepMeLoggedIn";
private static final String USERTYPE = "userType";
private ServiceRegistration loginModule;
private String repositoryId;
@Reference
private SlingRepository slingRepository;
@Reference
private SlingSettingsService slingSettings;
@Reference
private CODSService codsService;
@Activate
protected void activate(ComponentContext componentContext) {
LOGGER.debug("SASAuthnHandler : activate");
this.repositoryId = slingRepository.getDescriptor(REPO_DESC_CLUSTER_ID);
if (this.repositoryId == null || this.repositoryId.equalsIgnoreCase("")) {
this.repositoryId = slingRepository.getDescriptor(REPO_DESC_ID);
}
if (this.repositoryId == null || this.repositoryId.equalsIgnoreCase("")) {
this.repositoryId = slingSettings.getSlingId();
}
if (this.repositoryId == null || this.repositoryId.equalsIgnoreCase("")) {
this.repositoryId = UUID.randomUUID().toString();
LOGGER.warn("SASAuthnHandler : activate : Unable to get Repository ID; falling back to a random UUID.");
}
configure(componentContext.getProperties());
this.loginModule = null;
try {
this.loginModule = SASLoginModule.register(this,
componentContext.getBundleContext());
LOGGER.debug("SASAuthnHandler : activate : Registered SAS Login Module");
} catch (Throwable t) {
LOGGER.error("SASAuthnHandler : activate : Error in activation", t);
}
}
@Deactivate
protected void deactivate(
@SuppressWarnings("unused") ComponentContext componentContext) {
LOGGER.debug("SASAuthnHandler : deactivate");
if (loginModule != null) {
loginModule.unregister();
LOGGER.debug("SASAuthnHandler : deactivate : Unregistered SAS Login Module");
loginModule = null;
}
}
protected void configure(Dictionary < ? , ? > properties) {
}
public void dropCredentials(HttpServletRequest request,
HttpServletResponse response) {
LOGGER.debug("SASAuthnHandler : dropCredentials : start");
// Remove the CRX Login Token cookie from the request
TokenCookie.update(request, response, this.repositoryId, null, null, true);
}
public AuthenticationInfo extractCredentials(HttpServletRequest request,
HttpServletResponse response) {
LOGGER.debug("SASAuthnHandler : extractCredentials : start : " + request.getRequestURI());
final String usertype = request.getParameter(USERTYPE);
// Check if the request should be acted on
if (!REQUEST_METHOD.equals(request.getMethod()) || !request.getRequestURI().endsWith(REQUEST_URL_SUFFIX) || usertype == null) {
LOGGER.debug("SASAuthnHandler : extractCredentials : request ignored");
return null;
}
final String username = request.getParameter(USERNAME);
final String password = request.getParameter(PASSWORD);
// Check for mandatory params, although these should be validated in front-end
if (username == null || username.length() == 0 || password == null || password.length() == 0) {
LOGGER.debug("SASAuthnHandler : extractCredentials : mandatory params missing, returning fail auth");
return AuthenticationInfo.FAIL_AUTH;
}
if (!usertype.equalsIgnoreCase("CODS")) {
LOGGER.debug("SASAuthnHandler : extractCredentials : usertype not CODS");
return null;
}
LOGGER.info("SASAuthnHandler : extractCredentials : proceeding with authentication of [{}]", username);
// Authenticate against CODS through a service facade
boolean authenticated = false;
try {
authenticated = codsService.authenticate(username, password);
} catch (CODSServiceException e) {
LOGGER.error("SASAuthnHandler : extractCredentials : error authenticating against CODS : ", e);
}
if (authenticated) {
LOGGER.info("SASAuthnHandler : extractCredentials : user [{}] authenticated externally", username);
try {
LOGGER.debug("SASAuthnHandler : extractCredentials : create token and return");
AuthenticationInfo authnInfo = TokenUtil.createCredentials(request, response, slingRepository, username, true);
return authnInfo;
} catch (RepositoryException e) {
LOGGER.error("SASAuthnHandler : extractCredentials : Repository error authenticating user: {} ~> {}", username, e);
} finally {
}
}
LOGGER.debug("SASAuthnHandler : extractCredentials : CODS user not authenticated, returning fail auth");
return AuthenticationInfo.FAIL_AUTH;
}
public boolean requestCredentials(HttpServletRequest arg0,
HttpServletResponse arg1) {
LOGGER.debug("SASAuthnHandler : requestCredentials : start");
return false;
}
public boolean canHandle(Credentials credentials) {
LOGGER.debug("SASAuthnHandler : canHandle : start");
return true;
}
public boolean authenticate(Credentials credentials) {
LOGGER.debug("SASAuthnHandler : authenticate : start");
return true;
}
@Override
public boolean authenticationSucceeded(HttpServletRequest request, HttpServletResponse response, AuthenticationInfo authInfo) {
LOGGER.debug("SASAuthnHandler : authenticationSucceeded : start");
// Change the persistence mechanism
if (request.getParameter(KEEP_ME_LOGGED_IN) != null && request.getParameter(KEEP_ME_LOGGED_IN).equalsIgnoreCase("true")) {
LOGGER.info("SASAuthnHandler : authenticationSucceeded : keep the user logged-in");
TokenCookie tokenCookie = TokenCookie.fromRequest(request);
if (tokenCookie != null) {
LOGGER.info("SASAuthnHandler : authenticationSucceeded : token : " + tokenCookie.toString());
TokenCookie.setCookie(response, "login-token", tokenCookie.toString(), 63072000, "/", request.getServerName(), true, false);
}
}
// Redirect to resource
String resource = request.getParameter("resource");
LOGGER.info("SASAuthnHandler : authenticationSucceeded : resource = " + resource);
try {
response.sendRedirect(resource);
} catch (IOException e) {
LOGGER.error("SASAuthnHandler : authenticationSucceeded : send redirect", e);
}
return true;
}