/* * Copyright 2011 Future Systems * * 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.krakenapps.radius.protocol; import java.io.UnsupportedEncodingException; import java.net.InetAddress; import java.net.UnknownHostException; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; public abstract class RadiusAttribute { public abstract int getType(); public abstract byte[] getBytes(); /** * RADIUS RFC treats string as a binary data */ public static byte[] encodeString(int type, byte[] b) { // type, length, string ByteBuffer bb = ByteBuffer.allocate(2 + b.length); bb.put((byte) type); bb.put((byte) (2 + b.length)); bb.put(b); return bb.array(); } public static byte[] encodeInt(int type, int value) { ByteBuffer bb = ByteBuffer.allocate(6); bb.put((byte) type); bb.put((byte) 6); bb.putInt(value); return bb.array(); } public static byte[] encodeIp(int type, InetAddress ip) { ByteBuffer bb = ByteBuffer.allocate(6); bb.put((byte) type); bb.put((byte) 6); bb.put(ip.getAddress()); return bb.array(); } public static byte[] encodeText(int type, String text) { try { byte[] b = text.getBytes("utf-8"); int len = 2 + b.length; ByteBuffer bb = ByteBuffer.allocate(len); bb.put((byte) type); bb.put((byte) len); bb.put(b); return bb.array(); } catch (UnsupportedEncodingException e) { // not reachable return null; } } public static int decodeInt(byte[] b, int offset, int length) { int len = b[offset + 1]; if (len != 6) throw new IllegalArgumentException("invalid length (should be 6): " + len); if (len > length) throw new BufferUnderflowException(); ByteBuffer bb = ByteBuffer.wrap(b); bb.position(offset + 2); return bb.getInt(); } public static InetAddress decodeIp(byte[] b, int offset, int length) throws UnknownHostException { int len = b[offset + 1]; if (len != 6) throw new IllegalArgumentException("invalid length (should be 6): " + len); if (len > length) throw new BufferUnderflowException(); byte[] ip = new byte[] { b[2 + offset], b[3 + offset], b[4 + offset], b[5 + offset] }; return InetAddress.getByAddress(ip); } public static byte[] decodeString(byte[] b, int offset, int length) { int len = b[offset + 1]; ByteBuffer bb = ByteBuffer.allocate(len - 2); bb.put(b, offset + 2, len - 2); return bb.array(); } public static String decodeText(byte[] b, int offset, int length) { int len = b[offset + 1]; if (len < 3) throw new IllegalArgumentException("empty text is not allowed"); if (len > length) throw new BufferUnderflowException(); try { return new String(b, offset + 2, len - 2, "utf-8"); } catch (UnsupportedEncodingException e) { // not reachable return null; } } public static RadiusAttribute parse(byte[] authenticator, String sharedSecret, byte[] b, int offset, int length) throws UnknownHostException { int type = b[offset]; switch (type) { case 1: return new UserNameAttribute(b, offset, length); case 2: return new UserPasswordAttribute(authenticator, sharedSecret, b, offset, length); case 3: return new ChapPasswordAttribute(b, offset, length); case 4: return new NasIpAddressAttribute(b, offset, length); case 5: return new NasPortAttribute(b, offset, length); case 6: return new ServiceTypeAttribute(b, offset, length); case 7: return new FramedProtocolAttribute(b, offset, length); case 8: return new FramedIpAddressAttribute(b, offset, length); case 9: return new FramedIpNetmaskAttribute(b, offset, length); case 10: return new FramedRoutingAttribute(b, offset, length); case 11: return new FilterIdAttribute(b, offset, length); case 12: return new FramedMtuAttribute(b, offset, length); case 13: return new FramedCompressionAttribute(b, offset, length); case 14: return new LoginIpHostAttribute(b, offset, length); case 15: return new LoginServiceAttribute(b, offset, length); case 16: return new LoginTcpPortAttribute(b, offset, length); case 18: return new ReplyMessageAttribute(b, offset, length); case 19: return new CallbackNumberAttribute(b, offset, length); case 20: return new CallbackIdAttribute(b, offset, length); case 22: return new FramedRouteAttribute(b, offset, length); case 23: return new FramedIpxNetworkAttribute(b, offset, length); case 24: return new StateAttribute(b, offset, length); case 25: return new ClassAttribute(b, offset, length); case 26: return new VendorSpecificAttribute(b, offset, length); case 27: return new SessionTimeoutAttribute(b, offset, length); case 28: return new IdleTimeoutAttribute(b, offset, length); case 29: return new TerminationActionAttribute(b, offset, length); case 30: return new CalledStationIdAttribute(b, offset, length); case 31: return new CallingStationIdAttribute(b, offset, length); case 32: return new NasIdentifierAttribute(b, offset, length); case 33: return new ProxyStateAttribute(b, offset, length); case 34: return new LoginLatServiceAttribute(b, offset, length); case 35: return new LoginLatNodeAttribute(b, offset, length); case 36: return new LoginLatGroupAttribute(b, offset, length); case 37: return new FramedAppleTalkLinkAttribute(b, offset, length); case 38: return new FramedAppleTalkNetworkAttribute(b, offset, length); case 39: return new FramedAppleTalkZoneAttribute(b, offset, length); case 60: return new ChapChallengeAttribute(b, offset, length); case 61: return new NasPortTypeAttribute(b, offset, length); case 62: return new PortLimitAttribute(b, offset, length); case 63: return new LoginLatPortAttribute(b, offset, length); default: throw new UnsupportedOperationException(); } } @Override public String toString() { return "type=" + getType() + ", len=" + getBytes().length; } }