1919import java .lang .reflect .Constructor ;
2020import java .lang .reflect .InvocationTargetException ;
2121import java .util .ArrayList ;
22+ import java .util .Arrays ;
2223import java .util .List ;
24+ import java .util .Locale ;
2325import java .util .Map ;
2426import java .util .Objects ;
25-
26- import static org .elasticsearch .entitlement .runtime .policy .PolicyParserException .newPolicyParserException ;
27+ import java .util .function .Function ;
28+ import java .util .function .Predicate ;
29+ import java .util .stream .Collectors ;
30+ import java .util .stream .Stream ;
2731
2832/**
2933 * A parser to parse policy files for entitlements.
3034 */
3135public class PolicyParser {
3236
33- protected static final String entitlementPackageName = Entitlement .class .getPackage ().getName ();
37+ private static final Map <String , Class <?>> EXTERNAL_ENTITLEMENTS = Stream .of (FileEntitlement .class , CreateClassLoaderEntitlement .class )
38+ .collect (Collectors .toUnmodifiableMap (PolicyParser ::getEntitlementTypeName , Function .identity ()));
3439
3540 protected final XContentParser policyParser ;
3641 protected final String policyName ;
3742
43+ static String getEntitlementTypeName (Class <? extends Entitlement > entitlementClass ) {
44+ var entitlementClassName = entitlementClass .getSimpleName ();
45+
46+ if (entitlementClassName .endsWith ("Entitlement" ) == false ) {
47+ throw new IllegalArgumentException (
48+ entitlementClassName + " is not a valid Entitlement class name. A valid class name must end with 'Entitlement'"
49+ );
50+ }
51+
52+ var strippedClassName = entitlementClassName .substring (0 , entitlementClassName .indexOf ("Entitlement" ));
53+ return Arrays .stream (strippedClassName .split ("(?=\\ p{Lu})" ))
54+ .filter (Predicate .not (String ::isEmpty ))
55+ .map (s -> s .toLowerCase (Locale .ROOT ))
56+ .collect (Collectors .joining ("_" ));
57+ }
58+
3859 public PolicyParser (InputStream inputStream , String policyName ) throws IOException {
3960 this .policyParser = YamlXContent .yamlXContent .createParser (XContentParserConfiguration .EMPTY , Objects .requireNonNull (inputStream ));
4061 this .policyName = policyName ;
@@ -67,18 +88,23 @@ protected Scope parseScope(String scopeName) throws IOException {
6788 }
6889 List <Entitlement > entitlements = new ArrayList <>();
6990 while (policyParser .nextToken () != XContentParser .Token .END_ARRAY ) {
70- if (policyParser .currentToken () != XContentParser .Token .START_OBJECT ) {
71- throw newPolicyParserException (scopeName , "expected object <entitlement type>" );
72- }
73- if (policyParser .nextToken () != XContentParser .Token .FIELD_NAME ) {
91+ if (policyParser .currentToken () == XContentParser .Token .VALUE_STRING ) {
92+ String entitlementType = policyParser .text ();
93+ Entitlement entitlement = parseEntitlement (scopeName , entitlementType );
94+ entitlements .add (entitlement );
95+ } else if (policyParser .currentToken () == XContentParser .Token .START_OBJECT ) {
96+ if (policyParser .nextToken () != XContentParser .Token .FIELD_NAME ) {
97+ throw newPolicyParserException (scopeName , "expected object <entitlement type>" );
98+ }
99+ String entitlementType = policyParser .currentName ();
100+ Entitlement entitlement = parseEntitlement (scopeName , entitlementType );
101+ entitlements .add (entitlement );
102+ if (policyParser .nextToken () != XContentParser .Token .END_OBJECT ) {
103+ throw newPolicyParserException (scopeName , "expected closing object" );
104+ }
105+ } else {
74106 throw newPolicyParserException (scopeName , "expected object <entitlement type>" );
75107 }
76- String entitlementType = policyParser .currentName ();
77- Entitlement entitlement = parseEntitlement (scopeName , entitlementType );
78- entitlements .add (entitlement );
79- if (policyParser .nextToken () != XContentParser .Token .END_OBJECT ) {
80- throw newPolicyParserException (scopeName , "expected closing object" );
81- }
82108 }
83109 return new Scope (scopeName , entitlements );
84110 } catch (IOException ioe ) {
@@ -87,34 +113,29 @@ protected Scope parseScope(String scopeName) throws IOException {
87113 }
88114
89115 protected Entitlement parseEntitlement (String scopeName , String entitlementType ) throws IOException {
90- Class <?> entitlementClass ;
91- try {
92- entitlementClass = Class .forName (
93- entitlementPackageName
94- + "."
95- + Character .toUpperCase (entitlementType .charAt (0 ))
96- + entitlementType .substring (1 )
97- + "Entitlement"
98- );
99- } catch (ClassNotFoundException cnfe ) {
100- throw newPolicyParserException (scopeName , "unknown entitlement type [" + entitlementType + "]" );
101- }
102- if (Entitlement .class .isAssignableFrom (entitlementClass ) == false ) {
116+ Class <?> entitlementClass = EXTERNAL_ENTITLEMENTS .get (entitlementType );
117+
118+ if (entitlementClass == null ) {
103119 throw newPolicyParserException (scopeName , "unknown entitlement type [" + entitlementType + "]" );
104120 }
121+
105122 Constructor <?> entitlementConstructor = entitlementClass .getConstructors ()[0 ];
106123 ExternalEntitlement entitlementMetadata = entitlementConstructor .getAnnotation (ExternalEntitlement .class );
107124 if (entitlementMetadata == null ) {
108125 throw newPolicyParserException (scopeName , "unknown entitlement type [" + entitlementType + "]" );
109126 }
110127
111- if (policyParser .nextToken () != XContentParser .Token .START_OBJECT ) {
112- throw newPolicyParserException (scopeName , entitlementType , "expected entitlement parameters" );
128+ Class <?>[] parameterTypes = entitlementConstructor .getParameterTypes ();
129+ String [] parametersNames = entitlementMetadata .parameterNames ();
130+
131+ if (parameterTypes .length != 0 || parametersNames .length != 0 ) {
132+ if (policyParser .nextToken () != XContentParser .Token .START_OBJECT ) {
133+ throw newPolicyParserException (scopeName , entitlementType , "expected entitlement parameters" );
134+ }
113135 }
136+
114137 Map <String , Object > parsedValues = policyParser .map ();
115138
116- Class <?>[] parameterTypes = entitlementConstructor .getParameterTypes ();
117- String [] parametersNames = entitlementMetadata .parameterNames ();
118139 Object [] parameterValues = new Object [parameterTypes .length ];
119140 for (int parameterIndex = 0 ; parameterIndex < parameterTypes .length ; ++parameterIndex ) {
120141 String parameterName = parametersNames [parameterIndex ];
0 commit comments