Skip to content

Commit

Permalink
Formatting, clean up.
Browse files Browse the repository at this point in the history
  • Loading branch information
NathanSweet committed Feb 1, 2023
1 parent b112258 commit 33a0f91
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 131 deletions.
82 changes: 37 additions & 45 deletions src/com/esotericsoftware/yamlbeans/SafeYamlConfig.java
Original file line number Diff line number Diff line change
@@ -1,50 +1,42 @@
package com.esotericsoftware.yamlbeans;

package com.esotericsoftware.yamlbeans;

/**
* SafeYamlConfig extends YamlConfig and hard codes the read anchor and read class tag flags to false.
* When these flags are enabled, it is possible to perform a deserialization attack if the Yaml being parsed is from an
* untrusted source.
* Using SafeYamlConfig is the equivalent of using YamlConfig after setting
* yamlConfig.readConfig.setAnchors(false);
* yamlConfig.readConfig.setClassTags(false);
*
* It should be noted by setting these two values neither anchors or specifying class names are supported.
* It is still possible to deserialize back to a specific object, but you need to specify the Class type in the code.
* e.g
* SafeYamlConfig yamlConfig = new SafeYamlConfig();
* YamlReader reader = new YamlReader(yamlData.toString(),yamlConfig);
* Data data = reader.read(Data.class);
*
/** SafeYamlConfig extends YamlConfig and hard codes the read anchor and read class tag flags to false. When these flags are
* enabled, it is possible to perform a deserialization attack if the Yaml being parsed is from an untrusted source.
* <p>
* Using SafeYamlConfig is the equivalent of using YamlConfig after setting:
*
* <pre>
* yamlConfig.readConfig.setAnchors(false);
* yamlConfig.readConfig.setClassTags(false);
* </pre>
*
* It should be noted by setting these two values neither anchors or specifying class names are supported. It is still possible to
* deserialize back to a specific object, but you need to specify the Class type in the code. For example:
*
* <pre>
* SafeYamlConfig config = new SafeYamlConfig();
* YamlReader reader = new YamlReader(yamlData.toString(), config);
* Data data = reader.read(Data.class);
* </pre>
*/
public class SafeYamlConfig extends YamlConfig {


public SafeYamlConfig () {
super();
super.readConfig = new SafeReadConfig();
}

static public class SafeReadConfig extends ReadConfig {

public SafeReadConfig(){
super.anchors = false;
super.classTags = false;
}

@Override
public void setClassTags(boolean classTags) {
if(classTags) {
throw new IllegalArgumentException("Class Tags cannot be enabled in SafeYamlConfig.");
}
}

@Override
public void setAnchors(boolean anchors) {
if(anchors) {
throw new IllegalArgumentException("Anchors cannot be enabled in SafeYamlConfig.");
}
}
}

public SafeYamlConfig () {
super.readConfig = new SafeReadConfig();
}

static public class SafeReadConfig extends ReadConfig {
public SafeReadConfig () {
super.anchors = false;
super.classTags = false;
}

public void setClassTags (boolean classTags) {
if (classTags) throw new IllegalArgumentException("Class Tags cannot be enabled in SafeYamlConfig.");
}

public void setAnchors (boolean anchors) {
if (anchors) throw new IllegalArgumentException("Anchors cannot be enabled in SafeYamlConfig.");
}
}
}
7 changes: 2 additions & 5 deletions src/com/esotericsoftware/yamlbeans/YamlConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -267,9 +267,6 @@ static public class ReadConfig {
boolean autoMerge = true;
boolean classTags = true;
boolean guessNumberTypes;



boolean anchors = true;

ReadConfig () {
Expand Down Expand Up @@ -325,10 +322,10 @@ public void setGuessNumberTypes (boolean guessNumberTypes) {
this.guessNumberTypes = guessNumberTypes;
}

public void setAnchors(boolean anchors) {
/** When false, anchors in the YAML are ignored. Default is true. */
public void setAnchors (boolean anchors) {
this.anchors = anchors;
}

}

static class ConstructorParameters {
Expand Down
17 changes: 5 additions & 12 deletions src/com/esotericsoftware/yamlbeans/YamlReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,10 @@ public Object get (String alias) {
return anchors.get(alias);
}

private void addAnchor(String key, Object value) {
if(config.readConfig.anchors) {
anchors.put(key, value);
}
private void addAnchor (String key, Object value) {
if (config.readConfig.anchors) anchors.put(key, value);
}


public void close () throws IOException {
parser.close();
anchors.clear();
Expand Down Expand Up @@ -164,7 +161,7 @@ protected Object readValue (Class type, Class elementType, Class defaultType)
parser.getNextEvent();
anchor = ((AliasEvent)event).anchor;
Object value = anchors.get(anchor);
if (value == null&&config.readConfig.anchors) throw new YamlReaderException("Unknown anchor: " + anchor);
if (value == null && config.readConfig.anchors) throw new YamlReaderException("Unknown anchor: " + anchor);
return value;
case MAPPING_START:
case SEQUENCE_START:
Expand Down Expand Up @@ -244,9 +241,7 @@ private Object readValueInternal (Class type, Class elementType, String anchor)
if (value != null) {
Number number = valueConvertedNumber(value);
if (number != null) {
if (anchor != null) {
addAnchor(anchor, number);
}
if (anchor != null) addAnchor(anchor, number);
parser.getNextEvent();
return number;
}
Expand Down Expand Up @@ -291,9 +286,7 @@ private Object readValueInternal (Class type, Class elementType, String anchor)
convertedValue = Byte.decode(value);
} else
throw new YamlException("Unknown field type.");
if (anchor != null) {
addAnchor(anchor, convertedValue);
}
if (anchor != null) addAnchor(anchor, convertedValue);
return convertedValue;
} catch (Exception ex) {
throw new YamlReaderException("Unable to convert value to required type \"" + type + "\": " + value, ex);
Expand Down
128 changes: 59 additions & 69 deletions test/com/esotericsoftware/yamlbeans/SafeYamlConfigTest.java
Original file line number Diff line number Diff line change
@@ -1,79 +1,69 @@

package com.esotericsoftware.yamlbeans;

import org.junit.Test;
import static junit.framework.Assert.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import org.junit.Test;

public class SafeYamlConfigTest {


private static final String TESTOBJECT_TAG = "!com.esotericsoftware.yamlbeans.SafeYamlConfigTest$TestObject";
private static final String LINE_SEPARATOR = System.getProperty("line.separator");


@Test
public void testDeserializationOfClassTag() throws YamlException {
SafeYamlConfig yamlConfig = new SafeYamlConfig();
StringBuilder yamlData = new StringBuilder();
yamlData.append(TESTOBJECT_TAG).append(LINE_SEPARATOR)
.append("a: test").append(LINE_SEPARATOR);
YamlReader reader = new YamlReader(yamlData.toString(),yamlConfig);
Object data = reader.read();
assertTrue(data instanceof HashMap);
Map dataMap = (Map) data;
assertTrue(dataMap.containsKey("a"));
assertEquals("test",dataMap.get("a"));
}



@Test
public void testIgnoreAnchor() throws YamlException {
SafeYamlConfig yamlConfig = new SafeYamlConfig();
StringBuilder yamlData = new StringBuilder();
yamlData.append("oldest friend:").append(LINE_SEPARATOR)
.append(" &1 !contact").append(LINE_SEPARATOR)
.append(" name: Bob").append(LINE_SEPARATOR)
.append(" age: 29").append(LINE_SEPARATOR)
.append("best friend: *1").append(LINE_SEPARATOR);
YamlReader reader = new YamlReader(yamlData.toString(),yamlConfig);
Object data = reader.read();
assertTrue(data instanceof HashMap);
Map dataMap = (Map) data;
assertTrue(dataMap.containsKey("oldest friend"));
Map old = (Map) dataMap.get("oldest friend");
assertTrue(old.containsKey("name"));
assertEquals("Bob",old.get("name"));
assertNull(dataMap.get("best friend"));
}


static class TestObject {
private String a;
public int age;
public String name;
public Object object;
public List<Object> objects;

private TestObject() {
}

public TestObject(String a) {
this.a = a;
}

public String getA() {
return a;
}

public void setA(String a) {
this.a = a;
}
}
private static final String TESTOBJECT_TAG = "!com.esotericsoftware.yamlbeans.SafeYamlConfigTest$TestObject";
private static final String LINE_SEPARATOR = System.getProperty("line.separator");

@Test
public void testDeserializationOfClassTag () throws YamlException {
SafeYamlConfig yamlConfig = new SafeYamlConfig();
StringBuilder yamlData = new StringBuilder();
yamlData.append(TESTOBJECT_TAG).append(LINE_SEPARATOR).append("a: test").append(LINE_SEPARATOR);
YamlReader reader = new YamlReader(yamlData.toString(), yamlConfig);
Object data = reader.read();
assertTrue(data instanceof HashMap);
Map dataMap = (Map)data;
assertTrue(dataMap.containsKey("a"));
assertEquals("test", dataMap.get("a"));
}

@Test
public void testIgnoreAnchor () throws YamlException {
SafeYamlConfig yamlConfig = new SafeYamlConfig();
StringBuilder yamlData = new StringBuilder();
yamlData.append("oldest friend:").append(LINE_SEPARATOR).append(" &1 !contact").append(LINE_SEPARATOR)
.append(" name: Bob").append(LINE_SEPARATOR).append(" age: 29").append(LINE_SEPARATOR).append("best friend: *1")
.append(LINE_SEPARATOR);
YamlReader reader = new YamlReader(yamlData.toString(), yamlConfig);
Object data = reader.read();
assertTrue(data instanceof HashMap);
Map dataMap = (Map)data;
assertTrue(dataMap.containsKey("oldest friend"));
Map old = (Map)dataMap.get("oldest friend");
assertTrue(old.containsKey("name"));
assertEquals("Bob", old.get("name"));
assertNull(dataMap.get("best friend"));
}

static class TestObject {
private String a;
public int age;
public String name;
public Object object;
public List<Object> objects;

private TestObject () {
}

public TestObject (String a) {
this.a = a;
}

public String getA () {
return a;
}

public void setA (String a) {
this.a = a;
}
}
}

0 comments on commit 33a0f91

Please sign in to comment.