/*
* The contents of this file are subject to the terms of the Common Development and
* Distribution License (the License). You may not use this file except in compliance with the
* License.
*
* You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
* specific language governing permission and limitations under the License.
*
* When distributing Covered Software, include this CDDL Header Notice in each file and include
* the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
* Header, with the fields enclosed by brackets [] replaced by your own identifying
* information: "Portions copyright [year] [name of copyright owner]".
*
* Copyright 2015 ForgeRock AS.
*/
package com.sun.identity.authentication.audit;
import static com.sun.identity.authentication.util.ISAuthConstants.SHARED_STATE_USERNAME;
import static java.util.Collections.emptyMap;
import static org.forgerock.audit.events.AuthenticationAuditEventBuilder.Status.*;
import static org.forgerock.openam.audit.AuditConstants.AUTHENTICATION_TOPIC;
import static org.forgerock.openam.audit.AuditConstants.Component.AUTHENTICATION;
import static org.forgerock.openam.audit.AuditConstants.EntriesInfoFieldKey.AUTH_CONTROL_FLAG;
import static org.forgerock.openam.audit.AuditConstants.EventName.AM_LOGIN_MODULE_COMPLETED;
import static org.forgerock.openam.audit.AuditConstants.LOGIN_MODULE_CONTROL_FLAG;
import static org.forgerock.openam.audit.context.AuditRequestContext.getTransactionIdValue;
import static org.forgerock.openam.utils.StringUtils.isEmpty;
import static org.forgerock.openam.utils.StringUtils.isNotEmpty;
import com.sun.identity.authentication.service.LoginState;
import org.forgerock.audit.events.AuthenticationAuditEventBuilder.Status;
import org.forgerock.openam.audit.AMAuthenticationAuditEventBuilder;
import org.forgerock.openam.audit.AuditEventFactory;
import org.forgerock.openam.audit.AuditEventPublisher;
import org.forgerock.openam.audit.context.AuditRequestContext;
import org.forgerock.openam.audit.model.AuthenticationAuditEntry;
import javax.inject.Inject;
import java.security.Principal;
import java.util.Map;
/**
* This auditor is specifically aimed at constructing and logging authentication events for login modules.
*
* @since 13.0.0
*/
public class AuthenticationModuleEventAuditor extends AbstractAuthenticationEventAuditor {
/**
* Constructor for {@link AuthenticationModuleEventAuditor}.
*
* @param eventPublisher The publisher responsible for logging the events.
* @param eventFactory The factory that can be used to create the events.
*/
@Inject
public AuthenticationModuleEventAuditor(AuditEventPublisher eventPublisher, AuditEventFactory eventFactory) {
super(eventPublisher, eventFactory);
}
/**
* Log an authentication module successful completion event.
*
* @param loginState The login state object.
* @param principal The principal for this module.
* @param auditEntryDetail A map containing audit entry details.
*/
public void auditModuleSuccess(LoginState loginState, Principal principal,
AuthenticationAuditEntry auditEntryDetail) {
String realm = getRealmFromState(loginState);
if (eventPublisher.isAuditing(realm, AUTHENTICATION_TOPIC, AM_LOGIN_MODULE_COMPLETED)) {
String principalName = principal == null ? null : principal.getName();
String authId = getUserId(principalName, realm);
auditModuleEvent(loginState, realm, principalName, authId, SUCCESSFUL, auditEntryDetail);
}
}
/**
* Log an authentication module failure completion event.
*
* @param loginState The login state object.
* @param principal The principal for this module.
* @param auditEntryDetail A map containing audit entry details.
*/
public void auditModuleFailure(LoginState loginState, Principal principal,
AuthenticationAuditEntry auditEntryDetail) {
String realm = getRealmFromState(loginState);
if (eventPublisher.isAuditing(realm, AUTHENTICATION_TOPIC, AM_LOGIN_MODULE_COMPLETED)) {
String principalName = principal == null ? null : principal.getName();
Map sharedState = loginState == null ? emptyMap() : loginState.getSharedState();
String authId = getUserId(principalName, realm);
if ((isEmpty(principalName) || isEmpty(authId)) && sharedState.containsKey(SHARED_STATE_USERNAME)) {
principalName = (String) sharedState.get(SHARED_STATE_USERNAME);
authId = getUserId(principalName, realm);
}
auditModuleEvent(loginState, realm, principalName, authId, FAILED, auditEntryDetail);
}
}
private void auditModuleEvent(LoginState loginState, String realm, String principal, String userId,
Status result, AuthenticationAuditEntry auditEntryDetail) {
String controlFlag = AuditRequestContext.getProperty(LOGIN_MODULE_CONTROL_FLAG);
if (auditEntryDetail != null && isNotEmpty(controlFlag)) {
auditEntryDetail.addInfo(AUTH_CONTROL_FLAG, controlFlag);
}
AMAuthenticationAuditEventBuilder builder = eventFactory.authenticationEvent(realm)
.transactionId(getTransactionIdValue())
.component(AUTHENTICATION)
.eventName(AM_LOGIN_MODULE_COMPLETED)
.result(result)
.entry(auditEntryDetail)
.trackingIds(getTrackingIds(loginState))
.userId(userId)
.principal(principal);
eventPublisher.tryPublish(AUTHENTICATION_TOPIC, builder.toEvent());
}
}