/******************************************************************************* * This file is part of OpenNMS(R). * * Copyright (C) 2006-2011 The OpenNMS Group, Inc. * OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * * OpenNMS(R) is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * OpenNMS(R) is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenNMS(R). If not, see: * http://www.gnu.org/licenses/ * * For more information contact: * OpenNMS(R) Licensing <license@opennms.org> * http://www.opennms.org/ * http://www.opennms.com/ *******************************************************************************/ package org.opennms.protocols.radius.monitor; import java.net.InetAddress; import java.util.Map; import net.jradius.client.RadiusClient; import net.jradius.client.auth.CHAPAuthenticator; import net.jradius.client.auth.EAPMD5Authenticator; import net.jradius.client.auth.EAPMSCHAPv2Authenticator; import net.jradius.client.auth.MSCHAPv1Authenticator; import net.jradius.client.auth.MSCHAPv2Authenticator; import net.jradius.client.auth.PAPAuthenticator; import net.jradius.client.auth.RadiusAuthenticator; import net.jradius.dictionary.Attr_NASIdentifier; import net.jradius.dictionary.Attr_UserName; import net.jradius.dictionary.Attr_UserPassword; import net.jradius.packet.AccessAccept; import net.jradius.packet.AccessRequest; import net.jradius.packet.RadiusPacket; import net.jradius.packet.attribute.AttributeFactory; import net.jradius.packet.attribute.AttributeList; import org.apache.log4j.Level; import org.opennms.core.utils.LogUtils; import org.opennms.core.utils.ParameterMap; import org.opennms.core.utils.TimeoutTracker; import org.opennms.netmgt.model.PollStatus; import org.opennms.netmgt.poller.Distributable; import org.opennms.netmgt.poller.MonitoredService; import org.opennms.netmgt.poller.NetworkInterface; import org.opennms.netmgt.poller.monitors.AbstractServiceMonitor; /** * This Monitor is used to poll hosts supporting Radius Authentication. * This is done by sending a radius auth packet to the host. * If a valid radius ACCEPT response is received. * then the Radius service is considered available. * * @author <A HREF="mailto:jonathan@opennms.org">Jonathan Sartin</A> * @author <A HREF="mailto:ranger@opennms.org">Benjamin Reed</A> * @author <A HREF="http://www.opennms.org/">OpenNMS </A> */ @Distributable final public class RadiusAuthMonitor extends AbstractServiceMonitor { /** * Number of milliseconds to wait before timing out a radius AUTH request */ public static final int DEFAULT_TIMEOUT = 5000; /** * Default number of times to retry a test */ public static final int DEFAULT_RETRY = 0; /** * Default radius authentication port */ public static final int DEFAULT_AUTH_PORT = 1812; /** * Default radius accounting port */ public static final int DEFAULT_ACCT_PORT = 1813; /** * Default radius authentication type */ public static final String DEFAULT_AUTH_TYPE = "pap"; /** * Default user */ public static final String DEFAULT_USER = "OpenNMS"; /** * Default pasword */ public static final String DEFAULT_PASSWORD = "OpenNMS"; /** * Default secret */ public static final String DEFAULT_SECRET = "secret"; /** * Default NAS-ID */ public static final String DEFAULT_NASID ="opennms"; /** * Class constructor. * * @throws java.lang.ClassNotFoundException if any. * @throws java.lang.InstantiationException if any. * @throws java.lang.IllegalAccessException if any. */ public RadiusAuthMonitor() throws ClassNotFoundException, InstantiationException, IllegalAccessException { LogUtils.infof(this, "RadiusAuthMonitor class loaded"); } /** * {@inheritDoc} * * Radius Authentication Poller * * Note that the poller will return SERVICE_AVAILABLE only if the * authentication Request actually succeeds. A failed authentication * request will result in SERVICE_UNAVILABLE, although the radius * server may actually be up. * @see org.opennms.netmgt.poller.ServiceMonitor#SERVICE_AVAILABLE * @see org.opennms.netmgt.poller.ServiceMonitor#SERVICE_UNAVAILABLE * @see org.opennms.netmgt.poller.ServiceMonitor#SERVICE_UNRESPONSIVE * @see org.opennms.netmgt.poller.ServiceMonitor#SERVICE_AVAILABLE * @see org.opennms.netmgt.poller.ServiceMonitor#SERVICE_UNAVAILABLE * @see org.opennms.netmgt.poller.ServiceMonitor#SERVICE_UNRESPONSIVE * @see org.opennms.netmgt.poller.ServiceMonitor#SERVICE_AVAILABLE * @see org.opennms.netmgt.poller.ServiceMonitor#SERVICE_UNAVAILABLE * @see org.opennms.netmgt.poller.ServiceMonitor#SERVICE_UNRESPONSIVE */ public PollStatus poll(MonitoredService svc, Map<String, Object> parameters) { final NetworkInterface<InetAddress> iface = svc.getNetInterface(); // Assume that the service is down PollStatus status = PollStatus.unavailable(); if (parameters == null) { throw new NullPointerException(); } final TimeoutTracker tracker = new TimeoutTracker(parameters, DEFAULT_RETRY, DEFAULT_TIMEOUT); int authport = ParameterMap.getKeyedInteger(parameters, "authport", DEFAULT_AUTH_PORT); int acctport = ParameterMap.getKeyedInteger(parameters, "acctport", DEFAULT_ACCT_PORT); String user = ParameterMap.getKeyedString(parameters, "user", DEFAULT_USER); String password = ParameterMap.getKeyedString(parameters, "password", DEFAULT_PASSWORD); String secret = ParameterMap.getKeyedString(parameters, "secret", DEFAULT_SECRET); String authType = ParameterMap.getKeyedString(parameters, "authtype", DEFAULT_AUTH_TYPE); String nasid = ParameterMap.getKeyedString(parameters, "nasid", DEFAULT_NASID); InetAddress addr = iface.getAddress(); AttributeFactory.loadAttributeDictionary("net.jradius.dictionary.AttributeDictionaryImpl"); int timeout = convertTimeoutToSeconds(ParameterMap.getKeyedInteger(parameters, "timeout", DEFAULT_TIMEOUT)); try { final RadiusClient rc = new RadiusClient(addr, secret, authport, acctport, timeout); for (tracker.reset(); tracker.shouldRetry(); tracker.nextAttempt()) { final AttributeList attributes = new AttributeList(); attributes.add(new Attr_UserName(user)); attributes.add(new Attr_NASIdentifier(nasid)); attributes.add(new Attr_UserPassword(password)); final AccessRequest accessRequest = new AccessRequest(rc, attributes); final RadiusAuthenticator auth; if (authType.equalsIgnoreCase("chap")) { auth = new CHAPAuthenticator(); } else if (authType.equalsIgnoreCase("pap")) { auth = new PAPAuthenticator(); } else if (authType.equalsIgnoreCase("mschapv1")) { auth = new MSCHAPv1Authenticator(); } else if (authType.equalsIgnoreCase("mschapv2")) { auth = new MSCHAPv2Authenticator(); } else if (authType.equalsIgnoreCase("eapmd5") || authType.equalsIgnoreCase("eap-md5")) { auth = new EAPMD5Authenticator(); } else if (authType.equalsIgnoreCase("eapmschapv2") || authType.equalsIgnoreCase("eap-mschapv2")) { auth = new EAPMSCHAPv2Authenticator(); } else { return logDown(Level.ERROR, "Unknown authenticator type '" + authType + "'"); } tracker.startAttempt(); // The retry should be handled by the RadiusClient because otherwise it will thrown an exception. RadiusPacket reply = rc.authenticate(accessRequest, auth, ParameterMap.getKeyedInteger(parameters, "retry", DEFAULT_RETRY)); if (reply instanceof AccessAccept) { double responseTime = tracker.elapsedTimeInMillis(); status = PollStatus.available(responseTime); LogUtils.debugf(this, "Radius service is AVAILABLE on: %s", addr.getCanonicalHostName()); LogUtils.debugf(this, "poll: responseTime= %fms", responseTime); break; } else if (reply != null) { LogUtils.debugf(this, "response returned, but request was not accepted: %s", reply); } status = logDown(Level.ERROR, "Invalid RADIUS reply: " + reply); } } catch (final Throwable e) { status = logDown(Level.ERROR, "Error while attempting to connect to the RADIUS service on " + addr.getCanonicalHostName(), e); } return status; } private int convertTimeoutToSeconds(int timeout) { return timeout/1000 > 0 ? timeout/1000 : 1; } }