/* * JBoss, Home of Professional Open Source. * Copyright 2017 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.wildfly.security.audit; import static org.wildfly.common.Assert.checkNotNullParam; import static org.wildfly.security._private.ElytronMessages.audit; import java.io.IOException; import java.net.InetAddress; import java.util.logging.Level; import org.jboss.logmanager.ExtLogRecord; import org.jboss.logmanager.handlers.SyslogHandler; import org.jboss.logmanager.handlers.SyslogHandler.Facility; import org.jboss.logmanager.handlers.SyslogHandler.Protocol; import org.jboss.logmanager.handlers.TcpOutputStream; import javax.net.SocketFactory; /** * An {@link AuditEndpoint} that logs to syslog. * * @author <a href="mailto:darran.lofthouse@jboss.com">Darran Lofthouse</a> */ public class SyslogAuditEndpoint implements AuditEndpoint { private volatile boolean accepting = true; private final SyslogHandler syslogHandler; /** * Creates a new {@link AuditEndpoint} that logs to syslog. */ SyslogAuditEndpoint(Builder builder) throws IOException { SyslogHandler.Protocol protocol = builder.ssl ? Protocol.SSL_TCP : builder.tcp ? Protocol.TCP : Protocol.UDP; syslogHandler = new SyslogHandler(checkNotNullParam("serverAddress", builder.serverAddress), builder.port, Facility.SECURITY, null, protocol, checkNotNullParam("hostName", builder.hostName)); if (builder.tcp && builder.socketFactory != null) { syslogHandler.setOutputStream(new TcpOutputStream(builder.socketFactory, builder.serverAddress, builder.port) { // anonymous class to access protected constructor }); } } @Override public void accept(EventPriority t, String u) throws IOException { if (!accepting) return; synchronized(this) { if (!accepting) return; syslogHandler.doPublish(new ExtLogRecord(toLevel(t), u, SyslogAuditEndpoint.class.getName())); } } private static Level toLevel(EventPriority eventPriority) { switch (eventPriority) { case ALERT: case EMERGENCY: case CRITICAL: case ERROR: return Level.SEVERE; case WARNING: return Level.WARNING; case INFORMATIONAL: return Level.INFO; case OFF: throw audit.invalidEventPriority(eventPriority); default: return Level.FINEST; } } @Override public void close() throws IOException { accepting = false; synchronized(this) { syslogHandler.close(); } } public static Builder builder() { return new Builder(); } public static class Builder { private InetAddress serverAddress; private int port; private boolean ssl = false; private boolean tcp = true; private String hostName; private SocketFactory socketFactory = null; Builder() { } /** * Set the server address syslog messages should be sent to. * * @param serverAddress the server address syslog messages should be sent to. * @return this builder. */ public Builder setServerAddress(InetAddress serverAddress) { this.serverAddress = checkNotNullParam("serverAddress", serverAddress); return this; } /** * Set the port the syslog server is listening on. * * @param port the port the syslog server is listening on. * @return this builder. */ public Builder setPort(int port) { this.port = port; return this; } /** * Set if the communication should be using TCP. * * @param tcp if the communication should be using TCP. * @return this builder. */ public Builder setTcp(boolean tcp) { this.tcp = tcp; return this; } /** * Set if the communication should be using SSL. * * @param ssl if the communication should be using SSL. * @return this builder. */ public Builder setSsl(boolean ssl) { this.ssl = ssl; return this; } /** * Set {@link SocketFactory} for TCP connections - usually to provide configured {@link javax.net.ssl.SSLSocketFactory}. * * @param socketFactory the {@link SocketFactory} or {@code null} for default {@link SocketFactory}. * @return this builder. */ public Builder setSocketFactory(SocketFactory socketFactory) { this.socketFactory = socketFactory; return this; } /** * Set the host name that should be sent within the syslog messages. * * @param hostName the host name that should be sent within the syslog messages. * @return this builder. */ public Builder setHostName(String hostName) { this.hostName = checkNotNullParam("hostName", hostName); return this; } /** * Build a new {@link AuditEndpoint} configured to pass all messages using Syslog. * * @return a new {@link AuditEndpoint} configured to pass all messages using Syslog. * @throws IOException if an error occurs initialising the endpoint. */ public AuditEndpoint build() throws IOException { return new SyslogAuditEndpoint(this); } } }