184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington/*
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington * The contents of this file are subject to the terms of the Common Development and
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington * Distribution License (the License). You may not use this file except in compliance with the
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington * License.
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington *
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington * specific language governing permission and limitations under the License.
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington *
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington * When distributing Covered Software, include this CDDL Header Notice in each file and include
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington * Header, with the fields enclosed by brackets [] replaced by your own identifying
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington * information: "Portions copyright [year] [name of copyright owner]".
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington *
c299abfd457a72f3b93d443fe40ad36169e1c0a8Craig McDonnell * Copyright 2015-2016 ForgeRock AS.
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington */
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunningtonpackage org.forgerock.openam.audit;
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunningtonimport static org.forgerock.audit.events.AuditEventBuilder.EVENT_NAME;
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunningtonimport static org.forgerock.json.resource.Requests.newCreateRequest;
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunningtonimport static org.forgerock.json.resource.Resources.newInternalConnection;
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunningtonimport static org.forgerock.openam.audit.AuditConstants.EVENT_REALM;
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunningtonimport static org.forgerock.openam.utils.StringUtils.isBlank;
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunningtonimport com.sun.identity.shared.debug.Debug;
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunningtonimport org.forgerock.audit.events.AuditEvent;
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunningtonimport org.forgerock.json.JsonValue;
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunningtonimport org.forgerock.json.resource.Connection;
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunningtonimport org.forgerock.json.resource.CreateRequest;
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunningtonimport org.forgerock.json.resource.ResourceException;
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunningtonimport org.forgerock.json.resource.ServiceUnavailableException;
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunningtonimport org.forgerock.openam.audit.AuditConstants.EventName;
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunningtonimport org.forgerock.services.context.RootContext;
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunningtonimport javax.inject.Inject;
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunningtonimport javax.inject.Singleton;
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington/**
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington * Responsible for publishing locally created audit events to the AuditService.
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington *
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington * @since 13.0.0
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington */
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington@Singleton
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunningtonpublic class AuditEventPublisherImpl implements AuditEventPublisher {
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington private static Debug debug = Debug.getInstance("amAudit");
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington private final AuditServiceProvider auditServiceProvider;
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington /**
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington * Constructs a new {@code AuditEventPublisher}.
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington *
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington * @param auditServiceProvider A {@code AuditServiceProvider} instance.
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington */
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington @Inject
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington public AuditEventPublisherImpl(AuditServiceProvider auditServiceProvider) {
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington this.auditServiceProvider = auditServiceProvider;
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington }
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington @Override
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington public void tryPublish(String topic, AuditEvent auditEvent) {
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington try {
c299abfd457a72f3b93d443fe40ad36169e1c0a8Craig McDonnell String realm = getValue(auditEvent.getValue(), EVENT_REALM, null);
c299abfd457a72f3b93d443fe40ad36169e1c0a8Craig McDonnell if (isBlank(realm)) {
c299abfd457a72f3b93d443fe40ad36169e1c0a8Craig McDonnell publishToDefault(topic, auditEvent);
c299abfd457a72f3b93d443fe40ad36169e1c0a8Craig McDonnell } else {
c299abfd457a72f3b93d443fe40ad36169e1c0a8Craig McDonnell publishForRealm(realm, topic, auditEvent);
c299abfd457a72f3b93d443fe40ad36169e1c0a8Craig McDonnell }
c299abfd457a72f3b93d443fe40ad36169e1c0a8Craig McDonnell } catch (Exception e) {
c299abfd457a72f3b93d443fe40ad36169e1c0a8Craig McDonnell logException(e, topic, auditEvent);
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington }
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington }
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington @Override
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington public boolean isAuditing(String realm, String topic, EventName eventName) {
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington if (isBlank(realm)) {
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington return auditServiceProvider.getDefaultAuditService().isAuditEnabled(topic, eventName);
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington } else {
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington return auditServiceProvider.getAuditService(realm).isAuditEnabled(topic, eventName);
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington }
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington }
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington
c299abfd457a72f3b93d443fe40ad36169e1c0a8Craig McDonnell private void publishToDefault(String topic, AuditEvent auditEvent) throws ResourceException {
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington AMAuditService auditService = auditServiceProvider.getDefaultAuditService();
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington Connection connection = newInternalConnection(auditService);
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington CreateRequest request = newCreateRequest(topic, auditEvent.getValue());
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington
c299abfd457a72f3b93d443fe40ad36169e1c0a8Craig McDonnell connection.create(new RootContext(), request);
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington }
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington
c299abfd457a72f3b93d443fe40ad36169e1c0a8Craig McDonnell private void publishForRealm(String realm, String topic, AuditEvent auditEvent) throws ResourceException {
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington AMAuditService auditService = auditServiceProvider.getAuditService(realm);
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington Connection connection = newInternalConnection(auditService);
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington CreateRequest request = newCreateRequest(topic, auditEvent.getValue());
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington try {
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington connection.create(new RootContext(), request);
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington } catch (ServiceUnavailableException e) {
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington debug.message("Audit Service for realm {} is unavailable. Trying the default Audit Service.", realm, e);
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington publishToDefault(topic, auditEvent);
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington }
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington }
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington
c299abfd457a72f3b93d443fe40ad36169e1c0a8Craig McDonnell private void logException(Exception exception, String topic, AuditEvent auditEvent) {
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington final String eventName = getValue(auditEvent.getValue(), EVENT_NAME, "-unknown-");
c299abfd457a72f3b93d443fe40ad36169e1c0a8Craig McDonnell if (exception instanceof ResourceException) {
c299abfd457a72f3b93d443fe40ad36169e1c0a8Craig McDonnell debug.error("Unable to publish {} audit event '{}' due to error: {} [{}]",
c299abfd457a72f3b93d443fe40ad36169e1c0a8Craig McDonnell topic, eventName, exception.getMessage(), ((ResourceException) exception).getReason(), exception);
c299abfd457a72f3b93d443fe40ad36169e1c0a8Craig McDonnell } else {
c299abfd457a72f3b93d443fe40ad36169e1c0a8Craig McDonnell debug.error("Unable to publish {} audit event '{}' due to error: [{}]",
c299abfd457a72f3b93d443fe40ad36169e1c0a8Craig McDonnell topic, eventName, exception.getMessage(), exception);
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington }
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington }
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington private String getValue(JsonValue jsonValue, String key, String defaultValue) {
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington return jsonValue.isDefined(key) ? jsonValue.get(key).asString() : defaultValue;
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington }
184c2aab7c668e864d6a346cf2e53270f365f6e0Phill Cunnington}