001/* 002 * oauth2-oidc-sdk 003 * 004 * Copyright 2012-2020, Connect2id Ltd and contributors. 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 007 * this file except in compliance with the License. You may obtain a copy of the 008 * License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software distributed 013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 015 * specific language governing permissions and limitations under the License. 016 */ 017 018package com.nimbusds.openid.connect.sdk.federation.policy; 019 020 021import java.util.LinkedList; 022import java.util.List; 023import java.util.Map; 024 025import net.minidev.json.JSONObject; 026 027import com.nimbusds.oauth2.sdk.ParseException; 028import com.nimbusds.oauth2.sdk.util.CollectionUtils; 029import com.nimbusds.oauth2.sdk.util.StringUtils; 030import com.nimbusds.openid.connect.sdk.federation.policy.language.*; 031import com.nimbusds.openid.connect.sdk.federation.policy.operations.DefaultPolicyOperationCombinationValidator; 032import com.nimbusds.openid.connect.sdk.federation.policy.operations.DefaultPolicyOperationFactory; 033import com.nimbusds.openid.connect.sdk.federation.policy.operations.PolicyOperationCombinationValidator; 034import com.nimbusds.openid.connect.sdk.federation.policy.operations.PolicyOperationFactory; 035 036 037/** 038 * Policy entry for a metadata parameter. 039 * 040 * @see MetadataPolicy 041 * 042 * <p>Related specifications: 043 * 044 * <ul> 045 * <li>OpenID Connect Federation 1.0, section 4.1. 046 * </ul> 047 */ 048public class MetadataPolicyEntry implements Map.Entry<String, List<PolicyOperation>> { 049 050 051 /** 052 * The default policy operation factory. 053 */ 054 protected final static PolicyOperationFactory DEFAULT_POLICY_OPERATION_FACTORY = new DefaultPolicyOperationFactory(); 055 056 057 /** 058 * The default policy operation combination validator. 059 */ 060 protected final static PolicyOperationCombinationValidator DEFAULT_POLICY_COMBINATION_VALIDATOR = new DefaultPolicyOperationCombinationValidator(); 061 062 063 /** 064 * The parameter name. 065 */ 066 private final String parameterName; 067 068 069 /** 070 * The policy operations, empty list if none. 071 */ 072 private List<PolicyOperation> policyOperations; 073 074 075 /** 076 * Creates a new policy entry for a metadata parameter. 077 * 078 * @param parameterName The parameter name. Must not be 079 * {@code null}. 080 * @param policyOperations The policy operations, empty list or 081 * {@code null} if none. 082 */ 083 public MetadataPolicyEntry(final String parameterName, final List<PolicyOperation> policyOperations) { 084 if (StringUtils.isBlank(parameterName)) { 085 throw new IllegalArgumentException("The parameter name must not be null or empty"); 086 } 087 this.parameterName = parameterName; 088 this.policyOperations = policyOperations; 089 } 090 091 092 /** 093 * Returns the parameter name. 094 * @see #getKey() 095 * 096 * @return The parameter name. 097 */ 098 public String getParameterName() { 099 return getKey(); 100 } 101 102 103 /** 104 * @see #getParameterName() 105 */ 106 @Override 107 public String getKey() { 108 return parameterName; 109 } 110 111 112 /** 113 * Returns the policy operations. 114 * @see #getValue() 115 * 116 * @return The policy operations, empty list if none. 117 */ 118 public List<PolicyOperation> getPolicyOperations() { 119 return getValue(); 120 } 121 122 123 /** 124 * @see #getPolicyOperations() 125 */ 126 @Override 127 public List<PolicyOperation> getValue() { 128 return policyOperations; 129 } 130 131 132 @Override 133 public List<PolicyOperation> setValue(final List<PolicyOperation> policyOperations) { 134 throw new UnsupportedOperationException(); 135 } 136 137 138 /** 139 * Applies this policy entry for a metadata parameter to the specified 140 * value. 141 * 142 * @param value The parameter value, {@code null} if not specified. 143 * 144 * @return The resulting value, can be {@code null}. 145 * 146 * @throws PolicyViolationException On a policy violation. 147 */ 148 public Object apply(final Object value) 149 throws PolicyViolationException { 150 151 if (CollectionUtils.isEmpty(getValue())) { 152 // no ops 153 return value; 154 } 155 156 // Apply policy operations in list 157 Object updatedValue = value; 158 for (PolicyOperation op: getValue()) { 159 updatedValue = PolicyOperationApplication.apply(op, updatedValue); 160 } 161 return updatedValue; 162 } 163 164 165 /** 166 * Returns a JSON object representation of the policy operations for 167 * this entry. 168 * 169 * @return The JSON object keeping the ordering of the members. 170 */ 171 public JSONObject toJSONObject() { 172 173 if (CollectionUtils.isEmpty(getValue())) { 174 return null; 175 } 176 177 JSONObject jsonObject = new JSONObject(); 178 for (PolicyOperation operation: getValue()) { 179 // E.g. "subset_of": ["code", "code token", "code id_token"]} 180 jsonObject.put(operation.getOperationName().getValue(), configToJSONEntity(operation)); 181 } 182 183 return jsonObject; 184 } 185 186 187 private static Object configToJSONEntity(final PolicyOperation op) { 188 189 // The order matters 190 191 if (op instanceof StringConfiguration) { 192 Object value = ((StringConfiguration)op).getStringConfiguration(); 193 if (value != null) { 194 return value; 195 } 196 } 197 198 if (op instanceof StringListConfiguration) { 199 Object value = ((StringListConfiguration)op).getStringListConfiguration(); 200 if (value != null) { 201 return value; 202 } 203 } 204 205 if (op instanceof BooleanConfiguration) { 206 return ((BooleanConfiguration)op).getBooleanConfiguration(); 207 } 208 209 throw new IllegalArgumentException("Unsupported policy operation: " + op.getClass()); 210 211 } 212 213 214 /** 215 * Parses a policy entry for a metadata parameter. This method is 216 * intended for policies including non-standard 217 * {@link PolicyOperation}s. 218 * 219 * @param parameterName The parameter name. Must not be 220 * {@code null}. 221 * @param entrySpec The JSON object entry specification, 222 * must not be {@code null}. 223 * @param factory The policy operation factory. Must not 224 * be {@code null}. 225 * @param combinationValidator The policy operation combination 226 * validator. Must not be {@code null}. 227 * 228 * @return The policy entry for the metadata parameter. 229 * 230 * @throws ParseException On JSON parsing exception. 231 * @throws PolicyViolationException On a policy violation. 232 */ 233 public static MetadataPolicyEntry parse(final String parameterName, 234 final JSONObject entrySpec, 235 final PolicyOperationFactory factory, 236 final PolicyOperationCombinationValidator combinationValidator) 237 throws ParseException, PolicyViolationException { 238 239 List<PolicyOperation> policyOperations = new LinkedList<>(); 240 241 for (String opName: entrySpec.keySet()) { 242 PolicyOperation op = factory.createForName(new OperationName(opName)); 243 op.parseConfiguration(entrySpec.get(opName)); 244 policyOperations.add(op); 245 } 246 247 List<PolicyOperation> validatedPolicyOperations = combinationValidator.validate(policyOperations); 248 249 return new MetadataPolicyEntry(parameterName, validatedPolicyOperations); 250 } 251 252 253 /** 254 * Parses a policy entry for a metadata parameter. This method is 255 * intended for policies with standard {@link PolicyOperation}s only. 256 * Uses the default {@link DefaultPolicyOperationFactory policy 257 * operation} and {@link DefaultPolicyOperationCombinationValidator 258 * policy combination validator} factories. 259 * 260 * @param parameterName The parameter name. Must not be {@code null}. 261 * @param entrySpec The JSON object entry specification, must not 262 * be {@code null}. 263 * 264 * @return The policy entry for the metadata parameter. 265 * 266 * @throws ParseException On JSON parsing exception. 267 * @throws PolicyViolationException On a policy violation. 268 */ 269 public static MetadataPolicyEntry parse(final String parameterName, 270 final JSONObject entrySpec) 271 throws ParseException, PolicyViolationException { 272 273 return parse(parameterName, entrySpec, DEFAULT_POLICY_OPERATION_FACTORY, DEFAULT_POLICY_COMBINATION_VALIDATOR); 274 } 275}