Package org.tinyradius.util

Source Code of org.tinyradius.util.RadiusClient

/**
* $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);

}
TOP

Related Classes of org.tinyradius.util.RadiusClient

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.