001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2015-2016 ForgeRock AS.
015 */
016
017package org.forgerock.audit;
018
019import static org.forgerock.audit.AuditServiceBuilder.newAuditService;
020import static org.forgerock.audit.json.AuditJsonConfig.getJson;
021import static org.forgerock.audit.json.AuditJsonConfig.registerHandlerToService;
022import static org.forgerock.http.routing.RouteMatchers.requestUriMatcher;
023
024import java.io.IOException;
025import java.io.InputStream;
026
027import org.forgerock.audit.events.handlers.buffering.BatchPublisherFactory;
028import org.forgerock.audit.events.handlers.buffering.BatchPublisherFactoryImpl;
029import org.forgerock.audit.json.AuditJsonConfig;
030import org.forgerock.http.Client;
031import org.forgerock.http.Handler;
032import org.forgerock.http.HttpApplication;
033import org.forgerock.http.HttpApplicationException;
034import org.forgerock.http.handler.HttpClientHandler;
035import org.forgerock.http.io.Buffer;
036import org.forgerock.http.routing.Router;
037import org.forgerock.http.routing.RoutingMode;
038import org.forgerock.json.JsonValue;
039import org.forgerock.json.resource.Resources;
040import org.forgerock.json.resource.ServiceUnavailableException;
041import org.forgerock.json.resource.http.CrestHttp;
042import org.forgerock.util.Factory;
043import org.slf4j.Logger;
044import org.slf4j.LoggerFactory;
045
046/**
047 * Crest Application that instantiates the AuditService on the crest router.
048 */
049public final class AuditHttpApplication implements HttpApplication {
050
051    private static final Logger logger = LoggerFactory.getLogger(AuditHttpApplication.class);
052    /** Audit event handlers config location. */
053    public static final String AUDIT_EVENT_HANDLERS_CONFIG = "/conf/audit-event-handlers.json";
054    /** Event handlers key. */
055    public static final String EVENT_HANDLERS = "eventHandlers";
056    /** Root path for audit endpoints. */
057    public static final String AUDIT_ROOT_PATH = "/audit";
058
059    private AuditService auditService;
060
061    @Override
062    public Handler start() throws HttpApplicationException {
063        final Router router = new Router();
064        final AuditServiceConfiguration auditServiceConfiguration = loadAuditServiceConfiguration();
065
066        AuditServiceBuilder auditServiceBuilder = newAuditService();
067        auditServiceBuilder.withDependencyProvider(setupDependencies());
068        auditServiceBuilder.withConfiguration(auditServiceConfiguration);
069
070        try (final InputStream eventHandlersConfig = this.getClass().getResourceAsStream(AUDIT_EVENT_HANDLERS_CONFIG)) {
071            JsonValue auditEventHandlers = getJson(eventHandlersConfig).get(EVENT_HANDLERS);
072            for (final JsonValue handlerConfig : auditEventHandlers) {
073                try {
074                    registerHandlerToService(handlerConfig, auditServiceBuilder, this.getClass().getClassLoader());
075                } catch (Exception ex) {
076                    logger.error("Unable to register handler defined by config: " + handlerConfig, ex);
077                }
078            }
079        } catch (AuditException | IOException e) {
080            logger.error("Failed to read audit event handler configurations", e);
081            throw new HttpApplicationException(e);
082        }
083
084        auditService = auditServiceBuilder.build();
085        try {
086            auditService.startup();
087        } catch (ServiceUnavailableException e) {
088            logger.error("Unable to start audit service", e);
089            throw new HttpApplicationException(e);
090        }
091        router.addRoute(requestUriMatcher(RoutingMode.STARTS_WITH, AUDIT_ROOT_PATH),
092                CrestHttp.newHttpHandler(Resources.newInternalConnectionFactory(auditService)));
093        return router;
094    }
095
096    @Override
097    public Factory<Buffer> getBufferFactory() {
098        return null;
099    }
100
101    @Override
102    public void stop() {
103        if (auditService != null) {
104            auditService.shutdown();
105        }
106    }
107
108    private DependencyProvider setupDependencies() throws HttpApplicationException {
109        DependencyProviderBase dependencyProvider = new DependencyProviderBase();
110        dependencyProvider.register(Client.class, new Client(new HttpClientHandler()));
111        dependencyProvider.register(BatchPublisherFactory.class, new BatchPublisherFactoryImpl());
112        return dependencyProvider;
113    }
114
115    /** Loads the audit service configuration from JSON. */
116    private static AuditServiceConfiguration loadAuditServiceConfiguration() {
117        try (InputStream inputStream = getResourceAsStream("/conf/audit-service.json")) {
118            return AuditJsonConfig.parseAuditServiceConfiguration(inputStream);
119        } catch (AuditException | IOException e) {
120            final RuntimeException exception = new RuntimeException("Error while configuring the audit service", e);
121            logger.error(exception.getMessage(), e);
122            throw exception;
123        }
124    }
125
126    private static InputStream getResourceAsStream(String path) {
127        return AuditHttpApplication.class.getResourceAsStream(path);
128    }
129}