radiusclient.java

来自「TinyRadius is a simple, small and fast J」· Java 代码 · 共 342 行

JAVA
342
字号
/**
 * $Id: RadiusClient.java,v 1.7 2005/11/10 10:20:21 wuttke Exp $
 * Created on 09.04.2005
 * @author Matthias Wuttke
 * @version $Revision: 1.7 $
 */
package org.tinyradius.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.tinyradius.packet.AccessRequest;
import org.tinyradius.packet.AccountingRequest;
import org.tinyradius.packet.RadiusPacket;

/**
 * This object represents a simple Radius client which communicates with
 * a specified Radius server. You can use a single instance of this object
 * to authenticate or account different users with the same Radius server
 * as long as you authenticate/account one user after the other. This object
 * is thread safe, but only opens a single socket so operations using this
 * socket are synchronized to avoid confusion with the mapping of request
 * and result packets.
 */
public class RadiusClient {

	/**
	 * Creates a new Radius client object for a special Radius server.
	 * @param hostName host name of the Radius server
	 * @param sharedSecret shared secret used to secure the communication
	 */
	public RadiusClient(String hostName, String sharedSecret) {
		setHostName(hostName);
		setSharedSecret(sharedSecret);
	}
	
	/**
	 * Constructs a Radius client for the given Radius endpoint.
	 * @param client Radius endpoint
	 */
	public RadiusClient(RadiusEndpoint client) {
		this(client.getEndpointAddress().getAddress().getHostAddress(), client.getSharedSecret());		
	}
	
	/**
	 * Authenticates a user.
	 * @param userName user name
	 * @param password password
	 * @return true if authentication is successful, false otherwise
	 * @exception RadiusException malformed packet
	 * @exception IOException communication error (after getRetryCount()
	 * retries)
	 */
	public synchronized boolean authenticate(String userName, String password) 
	throws IOException, RadiusException {
		AccessRequest request = new AccessRequest(userName, password);
		RadiusPacket response = authenticate(request);
		return response.getPacketType() == RadiusPacket.ACCESS_ACCEPT;
	}
	
	/**
	 * Sends an Access-Request packet and receives a response
	 * packet.
	 * @param request request packet
	 * @return Radius response packet
	 * @exception RadiusException malformed packet
	 * @exception IOException communication error (after getRetryCount()
	 * retries)
	 */
	public synchronized RadiusPacket authenticate(AccessRequest request) 
	throws IOException, RadiusException {
		if (logger.isInfoEnabled())
			logger.info("send Access-Request packet: " + request);
		
		RadiusPacket response = communicate(request, getAuthPort());
		if (logger.isInfoEnabled())
			logger.info("received packet: " + response);
		
		return response;
	}
	
	/**
	 * Sends an Accounting-Request packet and receives a response
	 * packet.
	 * @param request request packet
	 * @return Radius response packet
	 * @exception RadiusException malformed packet
	 * @exception IOException communication error (after getRetryCount()
	 * retries)
	 */
	public synchronized RadiusPacket account(AccountingRequest request) 
	throws IOException, RadiusException {
		if (logger.isInfoEnabled())
			logger.info("send Accounting-Request packet: " + request);
		
		RadiusPacket response = communicate(request, getAcctPort());
		if (logger.isInfoEnabled())
			logger.info("received packet: " + response);
		
		return response;
	}

	/**
	 * Closes the socket of this client.
	 */
	public void close() {
		if (socket != null)
			socket.close();
	}
	
	/**
	 * Returns the Radius server auth port.
	 * @return auth port
	 */
	public int getAuthPort() {
		return authPort;
	}
	
	/**
	 * Sets the auth port of the Radius server.
	 * @param authPort auth port, 1-65535
	 */
	public void setAuthPort(int authPort) {
		if (authPort < 1 || authPort > 65535)
			throw new IllegalArgumentException("bad port number");
		this.authPort = authPort;
	}
	
	/**
	 * Returns the host name of the Radius server.
	 * @return host name
	 */
	public String getHostName() {
		return hostName;
	}

	/**
	 * Sets the host name of the Radius server.
	 * @param hostName host name
	 */
	public void setHostName(String hostName) {
		if (hostName == null || hostName.length() == 0)
			throw new IllegalArgumentException("host name must not be empty");
		this.hostName = hostName;
	}
	
	/**
	 * Returns the retry count for failed transmissions.
	 * @return retry count
	 */
	public int getRetryCount() {
		return retryCount;
	}
	
	/**
	 * Sets the retry count for failed transmissions.
	 * @param retryCount retry count, >0
	 */
	public void setRetryCount(int retryCount) {
		if (retryCount < 1)
			throw new IllegalArgumentException("retry count must be positive");
		this.retryCount = retryCount;
	}
	
	/**
	 * Returns the secret shared between server and client.
	 * @return shared secret
	 */
	public String getSharedSecret() {
		return sharedSecret;
	}
	
	/**
	 * Sets the secret shared between server and client.
	 * @param sharedSecret shared secret
	 */
	public void setSharedSecret(String sharedSecret) {
		if (sharedSecret == null || sharedSecret.length() == 0)
			throw new IllegalArgumentException("shared secret must not be empty");
		this.sharedSecret = sharedSecret;
	}
	
	/**
	 * Returns the socket timeout.
	 * @return socket timeout, ms
	 */
	public int getSocketTimeout() {
		return socketTimeout;
	}
	
	/**
	 * Sets the socket timeout
	 * @param socketTimeout timeout, ms, >0
	 * @throws SocketException
	 */
	public void setSocketTimeout(int socketTimeout)
	throws SocketException {
		if (socketTimeout < 1)
			throw new IllegalArgumentException("socket tiemout must be positive");
		this.socketTimeout = socketTimeout;
		if (socket != null)
			socket.setSoTimeout(socketTimeout);
	}
	
	/**
	 * Sets the Radius server accounting port.
	 * @param acctPort acct port, 1-65535
	 */
	public void setAcctPort(int acctPort) {
		if (acctPort < 1 || acctPort > 65535)
			throw new IllegalArgumentException("bad port number");
		this.acctPort = acctPort;
	}

	/**
	 * Returns the Radius server accounting port.
	 * @return acct port
	 */
	public int getAcctPort() {
		return acctPort;
	}
	
	/**
	 * Sends a Radius packet to the server and awaits an answer.
	 * @param request packet to be sent
	 * @param port server port number
	 * @return response Radius packet
	 * @exception RadiusException malformed packet
	 * @exception IOException communication error (after getRetryCount()
	 * retries)
	 */
	public RadiusPacket communicate(RadiusPacket request, int port) 
	throws IOException, RadiusException {
		DatagramPacket packetIn = new DatagramPacket(new byte[RadiusPacket.MAX_PACKET_LENGTH], RadiusPacket.MAX_PACKET_LENGTH);
		DatagramPacket packetOut = makeDatagramPacket(request, port);
		
		DatagramSocket socket = getSocket();
		for (int i = 1; i <= getRetryCount(); i++) {
			try {
				socket.send(packetOut);
				socket.receive(packetIn);
				return makeRadiusPacket(packetIn, request);
			} catch (IOException ioex) {
				if (i == getRetryCount()) {
					if (logger.isErrorEnabled()) {
						if (ioex instanceof SocketTimeoutException)
							logger.error("communication failure (timeout), no more retries");
						else
							logger.error("communication failure, no more retries", ioex);
					}
					throw ioex;
				}
				if (logger.isInfoEnabled())
					logger.info("communication failure, retry " + i);
				// TODO increase Acct-Delay-Time by getSocketTimeout()/1000
				// this changes the packet authenticator and requires packetOut to be
				// calculated again (call makeDatagramPacket)
            }
        }
		
		return null;
	}
	
	/**
	 * Sends the specified packet to the specified Radius server endpoint.
	 * @param remoteServer Radius endpoint consisting of server address,
	 * port number and shared secret
	 * @param request Radius packet to be sent 
	 * @return received response packet
	 * @throws RadiusException malformed packet
	 * @throws IOException error while communication
	 */
	public static RadiusPacket communicate(RadiusEndpoint remoteServer, RadiusPacket request) 
	throws RadiusException, IOException {
		RadiusClient rc = new RadiusClient(remoteServer);
		return rc.communicate(request, remoteServer.getEndpointAddress().getPort());
	}

	/**
	 * Returns the socket used for the server communication. It is
	 * bound to an arbitrary free local port number.
	 * @return local socket
	 * @throws SocketException
	 */
	protected DatagramSocket getSocket() 
	throws SocketException {
		if (socket == null) {
			socket = new DatagramSocket();
			socket.setSoTimeout(getSocketTimeout());
		}
		return socket;
	}
	
	/**
	 * Creates a datagram packet from a RadiusPacket to be send. 
	 * @param packet RadiusPacket
	 * @param port destination port number
	 * @return new datagram packet
	 * @throws IOException
	 */
	protected DatagramPacket makeDatagramPacket(RadiusPacket packet, int port) 
	throws IOException {
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		packet.encodeRequestPacket(bos, getSharedSecret());
		byte[] data = bos.toByteArray();
	
		InetAddress address = InetAddress.getByName(getHostName());
		DatagramPacket datagram = new DatagramPacket(data, data.length, address, port);
		return datagram;
	}
	
	/**
	 * Creates a RadiusPacket from a received datagram packet.
	 * @param packet received datagram
	 * @param request Radius request packet
	 * @return RadiusPacket object
	 */
	protected RadiusPacket makeRadiusPacket(DatagramPacket packet, RadiusPacket request) 
	throws IOException, RadiusException {
		ByteArrayInputStream in = new ByteArrayInputStream(packet.getData());
		return RadiusPacket.decodeResponsePacket(in, getSharedSecret(), request);
	}
	
	private int authPort = 1812;
	private int acctPort = 1813;
	private String hostName = null;
	private String sharedSecret = null;
	private DatagramSocket socket = null;
	private int retryCount = 3;
	private int socketTimeout = 3000;
	private static Log logger = LogFactory.getLog(RadiusClient.class);

}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?