Skip to content

Commit

Permalink
Merge pull request #334 from globalreachtech/support-custom-attribute…
Browse files Browse the repository at this point in the history
…-data-types

Support custom attribute data types
  • Loading branch information
horaceli authored May 9, 2024
2 parents eb7c499 + a535b8f commit 98d9982
Show file tree
Hide file tree
Showing 23 changed files with 304 additions and 196 deletions.
55 changes: 17 additions & 38 deletions src/main/java/org/tinyradius/core/attribute/AttributeTemplate.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
import io.netty.buffer.ByteBuf;
import org.tinyradius.core.RadiusPacketException;
import org.tinyradius.core.attribute.codec.AttributeCodecType;
import org.tinyradius.core.attribute.type.AttributeType;
import org.tinyradius.core.attribute.type.EncodedAttribute;
import org.tinyradius.core.attribute.type.OctetsAttribute;
import org.tinyradius.core.attribute.type.RadiusAttribute;
import org.tinyradius.core.attribute.type.RadiusAttributeFactory;
import org.tinyradius.core.dictionary.Dictionary;

import java.util.HashMap;
Expand All @@ -17,7 +17,6 @@
import static org.tinyradius.core.attribute.codec.AttributeCodecType.*;
import static org.tinyradius.core.attribute.rfc.Rfc2865.USER_PASSWORD;
import static org.tinyradius.core.attribute.rfc.Rfc2868.TUNNEL_PASSWORD;
import static org.tinyradius.core.attribute.type.VendorSpecificAttribute.VENDOR_SPECIFIC;

/**
* Represents a Radius attribute type.
Expand All @@ -32,52 +31,32 @@ public class AttributeTemplate {
private final boolean tagged;
private final AttributeCodecType codecType;

private final AttributeType decodedType;
private final AttributeType encodedType;
private final RadiusAttributeFactory<? extends RadiusAttribute> factory;

private final Map<Integer, String> int2str = new HashMap<>();
private final Map<String, Integer> str2int = new HashMap<>();

/**
* Create a new attribute type. Convenience method that assumes no encrypt and no Tag support.
*
* @param vendorId vendor ID or -1 if N/A
* @param type sub-attribute type code, as unsigned byte
* @param name sub-attribute name
* @param rawDataType string | octets | integer | date | ipaddr | ipv6addr | ipv6prefix
* @see AttributeTemplate#AttributeTemplate(int, int, String, String, byte, boolean)
*/
public AttributeTemplate(int vendorId, int type, String name, String rawDataType) {
this(vendorId, type, name, rawDataType, (byte) 0, false);
}

/**
* Create a new attribute type.
*
* @param vendorId vendor ID or -1 if N/A
* @param type sub-attribute type code, as unsigned byte
* @param name sub-attribute name
* @param rawDataType string | octets | integer | date | ipaddr | ipv6addr | ipv6prefix
* @param dataType string | octets | integer | date | ipaddr | ipv6addr | ipv6prefix
* @param encryptFlag encrypt flag as per FreeRadius dictionary format, can be 1/2/3, or default 0 for none
* @param hasTag whether attribute supports tags, as defined in RFC2868, default false
*/
public AttributeTemplate(int vendorId, int type, String name, String rawDataType, byte encryptFlag, boolean hasTag) {
public AttributeTemplate(int vendorId, int type, String name, String dataType, RadiusAttributeFactory<? extends RadiusAttribute> factory, byte encryptFlag, boolean hasTag) {
if (name == null || name.isEmpty())
throw new IllegalArgumentException("Name is empty");
requireNonNull(rawDataType, "Data type is null");
requireNonNull(dataType, "Data type is null");
this.vendorId = vendorId;
this.type = type;
this.name = name;
this.dataType = rawDataType.toLowerCase();

decodedType = vendorId == -1 && type == VENDOR_SPECIFIC ?
AttributeType.VSA :
AttributeType.fromDataType(this.dataType);

this.dataType = dataType.toLowerCase();
this.factory = factory;
this.tagged = detectHasTag(vendorId, type, hasTag);
this.codecType = detectAttributeCodec(vendorId, type, encryptFlag);
this.encodedType = this.codecType == NO_ENCRYPT ?
decodedType : AttributeType.OCTETS;
}

/**
Expand All @@ -89,7 +68,7 @@ public AttributeTemplate(int vendorId, int type, String name, String rawDataType
* @return new RadiusAttribute
*/
public RadiusAttribute create(Dictionary dictionary, byte tag, byte[] value) {
return decodedType.create(dictionary, vendorId, type, tag, value);
return factory.create(dictionary, vendorId, type, tag, value);
}

/**
Expand All @@ -101,7 +80,7 @@ public RadiusAttribute create(Dictionary dictionary, byte tag, byte[] value) {
* @return new RadiusAttribute
*/
public RadiusAttribute create(Dictionary dictionary, byte tag, String value) {
return decodedType.create(dictionary, vendorId, type, tag, value);
return factory.create(dictionary, vendorId, type, tag, value);
}

/**
Expand All @@ -115,7 +94,9 @@ public RadiusAttribute create(Dictionary dictionary, byte tag, String value) {
* @return new RadiusAttribute
*/
public RadiusAttribute parse(Dictionary dictionary, ByteBuf data) {
return autoWrapEncode(encodedType.create(dictionary, vendorId, data));
return isEncrypt() ?
new EncodedAttribute(OctetsAttribute.FACTORY.create(dictionary, vendorId, data)) :
factory.create(dictionary, vendorId, data);
}

/**
Expand All @@ -131,11 +112,9 @@ public RadiusAttribute parse(Dictionary dictionary, ByteBuf data) {
* @return new RadiusAttribute
*/
public RadiusAttribute createEncoded(Dictionary dictionary, byte tag, byte[] encodedValue) {
return autoWrapEncode(encodedType.create(dictionary, vendorId, type, tag, encodedValue));
}

private RadiusAttribute autoWrapEncode(OctetsAttribute attribute) {
return encryptEnabled() ? new EncodedAttribute(attribute) : attribute;
return isEncrypt() ?
new EncodedAttribute(OctetsAttribute.FACTORY.create(dictionary, vendorId, type, tag, encodedValue)) :
factory.create(dictionary, vendorId, type, tag, encodedValue);
}

/**
Expand Down Expand Up @@ -173,7 +152,7 @@ public boolean isTagged() {
return tagged;
}

public boolean encryptEnabled() {
public boolean isEncrypt() {
return codecType != NO_ENCRYPT;
}

Expand Down Expand Up @@ -225,7 +204,7 @@ public void addEnumerationValue(int num, String name) {
*/
public RadiusAttribute encode(RadiusAttribute attribute, byte[] requestAuth, String secret) throws RadiusPacketException {
// don't wrap in EncodedDecorator if not supported
if (!encryptEnabled() || attribute.isEncoded())
if (!isEncrypt() || attribute.isEncoded())
return attribute;

try {
Expand Down
26 changes: 26 additions & 0 deletions src/main/java/org/tinyradius/core/attribute/rfc/Rfc6572.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.tinyradius.core.attribute.rfc;

public class Rfc6572 {

private Rfc6572() {
}

public static final byte MOBILE_NODE_IDENTIFIER = (byte) 145;
public static final byte SERVICE_SELECTION = (byte) 146;
public static final byte PMIP6_HOME_LMA_IPV6_ADDRESS = (byte) 147;
public static final byte PMIP6_VISITED_LMA_IPV6_ADDRESS = (byte) 148;
public static final byte PMIP6_HOME_LMA_IPV4_ADDRESS = (byte) 149;
public static final byte PMIP6_VISITED_LMA_IPV4_ADDRESS = (byte) 150;
public static final byte PMIP6_HOME_HN_PREFIX = (byte) 151;
public static final byte PMIP6_VISITED_HN_PREFIX = (byte) 152;
public static final byte PMIP6_HOME_INTERFACE_ID = (byte) 153;
public static final byte PMIP6_VISITED_INTERFACE_ID = (byte) 154;
public static final byte PMIP6_HOME_IPV4_HOA = (byte) 155;
public static final byte PMIP6_VISITED_IPV4_HOA = (byte) 156;
public static final byte PMIP6_HOME_DHCP4_SERVER_ADDRESS = (byte) 157;
public static final byte PMIP6_VISITED_DHCP4_SERVER_ADDRESS = (byte) 158;
public static final byte PMIP6_HOME_DHCP6_SERVER_ADDRESS = (byte) 159;
public static final byte PMIP6_VISITED_DHCP6_SERVER_ADDRESS = (byte) 160;
public static final byte PMIP6_HOME_IPV4_GATEWAY = (byte) 161;
public static final byte PMIP6_VISITED_IPV4_GATEWAY = (byte) 162;
}
13 changes: 13 additions & 0 deletions src/main/java/org/tinyradius/core/attribute/rfc/Rfc6911.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.tinyradius.core.attribute.rfc;

public class Rfc6911 {

private Rfc6911() {
}

public static final byte FRAMED_IPV6_ADDRESS = (byte) 168;
public static final byte DNS_SERVER_IPV6_ADDRESS = (byte) 169;
public static final byte ROUTE_IPV6_INFORMATION = (byte) 170;
public static final byte DELEGATED_IPV6_PREFIX_POOL = (byte) 171;
public static final byte STATEFUL_IPV6_ADDRESS_POOL = (byte) 172;
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
import java.nio.ByteBuffer;

/**
* This class represents a Radius attribute which only contains a 32 bit integer.
* This class represents a Radius attribute which only contains a 32-bit integer.
*/
public class IntegerAttribute extends OctetsAttribute {

public static final RadiusAttributeFactory<IntegerAttribute> FACTORY = new Factory();

public IntegerAttribute(Dictionary dictionary, int vendorId, ByteBuf data) {
super(dictionary, vendorId, data);
if (!isTagged() && getValue().length != 4)
Expand Down Expand Up @@ -65,4 +67,17 @@ public static byte[] stringParser(Dictionary dictionary, int vendorId, int type,
.orElse(byteBuf)
.array();
}

private static class Factory implements RadiusAttributeFactory<IntegerAttribute> {

@Override
public IntegerAttribute newInstance(Dictionary dictionary, int vendorId, ByteBuf value) {
return new IntegerAttribute(dictionary, vendorId, value);
}

@Override
public byte[] parse(Dictionary dictionary, int vendorId, int type, String value) {
return IntegerAttribute.stringParser(dictionary, vendorId, type, value);
}
}
}
30 changes: 30 additions & 0 deletions src/main/java/org/tinyradius/core/attribute/type/IpAttribute.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ public String getValueString() {
* IPv4 Address
*/
public static class V4 extends IpAttribute {
public static final RadiusAttributeFactory<V4> FACTORY = new Factory();

public V4(Dictionary dictionary, int vendorId, ByteBuf data) {
super(dictionary, vendorId, data);
if (getValue().length != 4)
Expand All @@ -53,16 +55,44 @@ public V4(Dictionary dictionary, int vendorId, ByteBuf data) {
public int getValueInt() {
return ByteBuffer.wrap(getValue()).getInt();
}

private static class Factory implements RadiusAttributeFactory<V4> {

@Override
public V4 newInstance(Dictionary dictionary, int vendorId, ByteBuf value) {
return new V4(dictionary, vendorId, value);
}

@Override
public byte[] parse(Dictionary dictionary, int vendorId, int type, String value) {
return IpAttribute.stringParser(value);
}
}
}

/**
* IPv6 Address
*/
public static class V6 extends IpAttribute {
public static final RadiusAttributeFactory<V6> FACTORY = new Factory();

public V6(Dictionary dictionary, int vendorId, ByteBuf data) {
super(dictionary, vendorId, data);
if (getValue().length != 16)
throw new IllegalArgumentException("IPv6 address should be 16 octets, actual: " + getValue().length);
}

private static class Factory implements RadiusAttributeFactory<V6> {

@Override
public V6 newInstance(Dictionary dictionary, int vendorId, ByteBuf value) {
return new V6(dictionary, vendorId, value);
}

@Override
public byte[] parse(Dictionary dictionary, int vendorId, int type, String value) {
return IpAttribute.stringParser(value);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
*/
public class Ipv6PrefixAttribute extends OctetsAttribute {

public static final RadiusAttributeFactory<Ipv6PrefixAttribute> FACTORY = new Factory();

public Ipv6PrefixAttribute(Dictionary dictionary, int vendorId, ByteBuf data) {
super(dictionary, vendorId, data);
final byte[] value = getValue();
Expand Down Expand Up @@ -102,4 +104,17 @@ public String getValueString() {
public static byte[] stringParser(String value) {
return validate(convertString(value), Integer.parseInt(value.split("/")[1]));
}

private static class Factory implements RadiusAttributeFactory<Ipv6PrefixAttribute> {

@Override
public Ipv6PrefixAttribute newInstance(Dictionary dictionary, int vendorId, ByteBuf value) {
return new Ipv6PrefixAttribute(dictionary, vendorId, value);
}

@Override
public byte[] parse(Dictionary dictionary, int vendorId, int type, String value) {
return Ipv6PrefixAttribute.stringParser(value);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
*/
public class OctetsAttribute implements RadiusAttribute {

public static final RadiusAttributeFactory<OctetsAttribute> FACTORY = new Factory();

private final Dictionary dictionary;

private final ByteBuf data;
Expand Down Expand Up @@ -129,4 +131,18 @@ public int hashCode() {
public static byte[] stringHexParser(String value) {
return DatatypeConverter.parseHexBinary(value);
}

private static class Factory implements RadiusAttributeFactory<OctetsAttribute> {

@Override
public OctetsAttribute newInstance(Dictionary dictionary, int vendorId, ByteBuf value) {
return new OctetsAttribute(dictionary, vendorId, value);
}

@Override
public byte[] parse(Dictionary dictionary, int vendorId, int type, String value) {
return stringHexParser(value);
}
}

}
Loading

0 comments on commit 98d9982

Please sign in to comment.