All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.identity.cli.LogWriter Maven / Gradle / Ivy

There is a newer version: 15.1.3
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2006 Sun Microsystems Inc. All Rights Reserved
 *
 * 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
 * https://opensso.dev.java.net/public/CDDLv1.0.html or
 * opensso/legal/CDDLv1.0.txt
 * See the License for the specific language governing
 * permission and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL
 * Header Notice in each file and include the License file
 * at opensso/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 Copyrighted [year] [name of copyright owner]"
 *
 * $Id: LogWriter.java,v 1.3 2008/06/25 05:42:09 qcheng Exp $
 *
 * Portions Copyrighted 2015-2016 ForgeRock AS.
 */

package com.sun.identity.cli;


import static org.forgerock.audit.events.AuthenticationAuditEventBuilder.Status.*;
import static org.forgerock.http.routing.Version.*;
import static org.forgerock.json.JsonValue.*;
import static org.forgerock.openam.audit.AuditConstants.*;
import static org.forgerock.openam.utils.Time.*;

import java.io.IOException;
import java.net.URISyntaxException;
import java.security.AccessController;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;

import org.forgerock.audit.events.AccessAuditEventBuilder;
import com.google.common.collect.ImmutableMap;
import org.forgerock.guice.core.InjectorHolder;
import org.forgerock.http.Client;
import org.forgerock.http.HttpApplicationException;
import org.forgerock.http.header.AcceptApiVersionHeader;
import org.forgerock.http.protocol.Request;
import org.forgerock.http.protocol.Response;
import org.forgerock.json.JsonValue;
import org.forgerock.openam.audit.AMAccessAuditEventBuilder;
import org.forgerock.openam.audit.AMAuditEventBuilder;
import org.forgerock.openam.audit.AMAuthenticationAuditEventBuilder;
import org.forgerock.openam.audit.AuditConstants;
import org.forgerock.util.Function;
import org.forgerock.util.promise.NeverThrowsException;
import org.slf4j.LoggerFactory;

import com.iplanet.am.util.SystemProperties;
import com.iplanet.dpro.session.SessionID;
import com.iplanet.services.naming.WebtopNaming;
import com.iplanet.sso.SSOToken;
import com.sun.identity.log.LogRecord;
import com.sun.identity.log.Logger;
import com.sun.identity.log.messageid.LogMessageID;
import com.sun.identity.log.messageid.LogMessageProvider;
import com.sun.identity.log.messageid.MessageProviderFactory;
import com.sun.identity.security.AdminTokenAction;
import com.sun.identity.shared.debug.Debug;

/**
 * Writes audit log entries.
 */
public class LogWriter {

    private static final Debug DEBUG = Debug.getInstance("amCLI");

    private static final String LOG_MSG_XML = "CLI";

    /**
     * Access Log Type.
     */
    public final static int LOG_ACCESS = 0;

    /**
     * Error Log Type.
     */
    public final static int LOG_ERROR = 1;
    private static final List IGNORED_LOG_FIELDS = Arrays.asList("error message", "realm", "user id");

    private static final Map NORMALIZED_FIELD_NAMES = new ImmutableMap.Builder()
            .put("name of realm", "realm")
            .put("realm where entity resides", "realm")
            .put("realm where circle of trust resides", "realm")
            .build();
    private static final Client client = InjectorHolder.getInstance(Client.class);

    private LogWriter() {
    }

    /**
     * Writes to log.
     *
     * @param mgr Command Manager Object.
     * @param type Type of log message.
     * @param level Logging level of the message.
     * @param msgid ID for message.
     * @param msgdata array of log message "data".
     * @param ssoToken Single Sign On Token of the user who committed the
     *        operation.
     * @throws CLIException if log cannot be written.
     */
    public static void log(
        CommandManager mgr,
        int type,
        Level level,
        String msgid,
        String[] msgdata,
        SSOToken ssoToken
    ) throws CLIException {
        if (!mgr.isLogOff()) {
            Logger logger;
            String logName = mgr.getLogName();
            switch (type) {
                case LOG_ERROR:
                    logger = (com.sun.identity.log.Logger) Logger.getLogger(logName + ".error");
                    break;
                default:
                    logger = (com.sun.identity.log.Logger) Logger.getLogger(logName + ".access");
            }
            try {
                LogMessageProvider msgProvider = MessageProviderFactory.getProvider(LOG_MSG_XML);
                SSOToken adminSSOToken = AccessController.doPrivileged(AdminTokenAction.getInstance());
                if (ssoToken == null) {
                    ssoToken = adminSSOToken;
                }

                if (logger.isLoggable(level)) {
                    LogRecord logRec = msgProvider.createLogRecord(msgid, msgdata, ssoToken);
                    if (logRec != null) {
                        logger.log(logRec, adminSSOToken);
                    }
                }

                logToAuditService(type, msgid, msgdata, ssoToken, msgProvider, adminSSOToken);
            } catch (Exception e) {
                throw new CLIException(e, ExitCodes.CANNOT_WRITE_LOG);
            }
        }
    }

    private static void logToAuditService(int type, String msgid, String[] msgdata, SSOToken ssoToken,
            LogMessageProvider msgProvider, SSOToken adminSSOToken) throws Exception {
        String operation = msgid.substring(msgid.indexOf('_') + 1);
        LogMessageID logMessageID = msgProvider.getAllHashMessageIDs().get(msgid);
        if (logMessageID == null) {
            DEBUG.error("Attempted audit logging for unknown message ID {}", msgid);
            return;
        }
        List fields = logMessageID.getDataColumns();

        AMAuditEventBuilder builder;
        String topic;
        if ("LOGIN".equals(operation) && !msgid.startsWith("ATTEMPT")) {
            builder = authenticationEventBuilder(type, msgid, fields, msgdata);
            topic = AuditConstants.AUTHENTICATION_TOPIC;
        } else if (!"LOGIN".equals(operation)) {
            builder = accessEventBuilder(type, msgid, msgdata, operation, fields);
            topic = AuditConstants.ACCESS_TOPIC;
        } else {
            return;
        }

        JsonValue eventJson = builder.transactionId(CommandManager.TRANSACTION_ID.getValue())
                .timestamp(currentTimeMillis())
                .userId(ssoToken.getPrincipal().getName())
                .trackingIdFromSSOToken(ssoToken)
                .component(AuditConstants.Component.SSOADM)
                .toEvent().getValue();

        String sessionId = adminSSOToken.getTokenID().toString();
        sendEvent(topic, eventJson, sessionId, WebtopNaming.mapSiteToServer(new SessionID(sessionId)));
    }

    private static void sendEvent(String topic, JsonValue eventJson, String sessionId, String baseUrl) throws HttpApplicationException, URISyntaxException {
        Request request = new Request();
        request.setMethod("POST");
        if (eventJson.isDefined(EVENT_REALM)) {
            String realm = eventJson.get(EVENT_REALM).asString();
            baseUrl = baseUrl + "/json/realm-audit" + (realm.endsWith("/") ? realm : realm + "/");
        } else {
            baseUrl = baseUrl + "/json/global-audit/";
        }
        request.setUri(baseUrl + topic + "?_action=create");
        request.getHeaders().add(SystemProperties.get("com.iplanet.am.cookie.name"), sessionId);
        request.getHeaders().add(new AcceptApiVersionHeader(version(1), version(1)));
        request.getEntity().setJson(eventJson.getObject());
        client.send(request).then(WARN_OF_FAILURES_FUNCTION);
    }

    private static AMAccessAuditEventBuilder accessEventBuilder(int type, String msgid, String[] msgdata,
            String operation, List fields) {
        AMAccessAuditEventBuilder accessEventBuilder = new AMAccessAuditEventBuilder();
        String realm = null;
        JsonValue requestData = json(object());
        if (msgdata != null) {
            for (int i = 0; i < msgdata.length; i++) {
                String fieldName = fields.get(i).toLowerCase();
                if (NORMALIZED_FIELD_NAMES.containsKey(fieldName)) {
                    fieldName = NORMALIZED_FIELD_NAMES.get(fieldName);
                }
                if (!IGNORED_LOG_FIELDS.contains(fieldName)) {
                    requestData.put(fieldName, msgdata[i]);
                } else if (fieldName.equals("realm")) {
                    realm = msgdata[i];
                }
            }
        }
        accessEventBuilder.request("ssoadm", operation, requestData);
        if (type == LOG_ERROR) {
            int errorMessageIndex = fields.indexOf("error message");
            if (errorMessageIndex > -1) {
                accessEventBuilder.responseWithDetail(AccessAuditEventBuilder.ResponseStatus.FAILED,
                        null, json(object(field("message", msgdata[errorMessageIndex]))));
            } else {
                accessEventBuilder.response(AccessAuditEventBuilder.ResponseStatus.FAILED, null);
            }
            accessEventBuilder.eventName(AuditConstants.EventName.AM_ACCESS_OUTCOME);
        } else if (msgid.startsWith("SUCCEED")) {
            accessEventBuilder.response(AccessAuditEventBuilder.ResponseStatus.SUCCESSFUL, null);
            accessEventBuilder.eventName(AuditConstants.EventName.AM_ACCESS_OUTCOME);
        } else {
            accessEventBuilder.eventName(AuditConstants.EventName.AM_ACCESS_ATTEMPT);
        }

        if (realm != null) {
            accessEventBuilder.realm(realm);
        }
        return accessEventBuilder;
    }

    private static AMAuthenticationAuditEventBuilder authenticationEventBuilder(int type, String msgid, List fields,
            String[] principal) {
        AMAuthenticationAuditEventBuilder authEventBuilder = new AMAuthenticationAuditEventBuilder()
                .principal(principal[fields.indexOf("user ID")]);
        if (!msgid.startsWith("ATTEMPT")) {
            authEventBuilder.result(type == LOG_ERROR ? FAILED : SUCCESSFUL);
        }
        return authEventBuilder.eventName(AuditConstants.EventName.AM_LOGIN_COMPLETED);
    }

    private static Function WARN_OF_FAILURES_FUNCTION =
            new Function() {
                private final org.slf4j.Logger logger = LoggerFactory.getLogger("amAudit");
                @Override
                public Void apply(Response response) throws NeverThrowsException {
                    if (!response.getStatus().isSuccessful()) {
                        String responseText;
                        try {
                            responseText = response.getEntity().getString();
                        } catch (IOException e) {
                            responseText = "--unknown--";
                        }
                        logger.warn("Could not log audit via REST API: Status: {}, Response: {}",
                                response.getStatus(), responseText);
                    }
                    response.close();
                    return null;
                }
            };
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy