/**
* Licensed to The Apereo Foundation under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
*
* The Apereo Foundation licenses this file to you under the Educational
* Community 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://opensource.org/licenses/ecl2.txt
*
* 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.opencastproject.urlsigning.utils;
import org.opencastproject.urlsigning.common.Policy;
import org.apache.commons.codec.binary.Base64;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.TreeMap;
/**
* A Utility class to encode / decode Policy files from and to Base 64 and Json.
*/
public final class PolicyUtils {
/** The JSON key for object that contains the date and ip conditions for the resource. */
private static final String CONDITION_KEY = "Condition";
/** The JSON key for the date and time the resource will become available. */
private static final String DATE_GREATER_THAN_KEY = "DateGreaterThan";
/** The JSON key for the date and time the resource will no longer be available. */
private static final String DATE_LESS_THAN_KEY = "DateLessThan";
/** The JSON key for the IP address of the acceptable client. */
private static final String IP_ADDRESS_KEY = "IpAddress";
/** The JSON key for the base url for the resource. */
private static final String RESOURCE_KEY = "Resource";
/** The JSON key for the main object of the policy. */
private static final String STATEMENT_KEY = "Statement";
/** Parser used to parse policy content */
private static JSONParser jsonParser = new JSONParser();
private PolicyUtils() {
}
/**
* Encode a {@link String} into Base 64 encoding
*
* @param value
* The {@link String} to encode into base 64 encoding
* @return The {@link String} encoded into base 64.
*/
public static String base64Encode(String value) {
return Base64.encodeBase64URLSafeString(value.getBytes());
}
/**
* Decode a {@link String} from Base 64 encoding
*
* @param value
* The {@link String} to encode into Base 64
* @return The {@link String} decoded from base 64.
*/
public static String base64Decode(String value) {
return new String(Base64.decodeBase64(value), StandardCharsets.UTF_8);
}
/**
* Encode a byte[] into Base 64 encoding
*
* @param value
* The byte[] to encode into base 64 encoding
* @return The {@link String} encoded into base 64.
*/
public static String base64Encode(byte[] value) {
return new String(Base64.encodeBase64URLSafe(value), StandardCharsets.UTF_8);
}
/**
* Get a {@link Policy} from JSON data.
*
* @param policyJson
* The {@link String} representation of the json.
* @return A new {@link Policy} object populated from the JSON.
*/
public static Policy fromJson(String policyJson) {
JSONObject jsonPolicy = null;
try {
jsonPolicy = (JSONObject) jsonParser.parse(policyJson);
} catch (ParseException e) {
e.printStackTrace();
}
JSONObject statement = (JSONObject) jsonPolicy.get(STATEMENT_KEY);
String resource = statement.get(RESOURCE_KEY).toString();
JSONObject condition = (JSONObject) statement.get(CONDITION_KEY);
final String lessThanString = condition.get(DATE_LESS_THAN_KEY).toString();
final DateTime dateLessThan = new DateTime(Long.parseLong(lessThanString), DateTimeZone.UTC);
final DateTime dateGreaterThan;
Object greaterThanString = condition.get(DATE_GREATER_THAN_KEY);
if (greaterThanString != null) {
dateGreaterThan = new DateTime(Long.parseLong(greaterThanString.toString()), DateTimeZone.UTC);
} else {
dateGreaterThan = null;
}
return Policy.mkPolicyValidFromWithIP(resource, dateLessThan, dateGreaterThan,
(String) condition.get(IP_ADDRESS_KEY));
}
/**
* Render a {@link Policy} into JSON.
*
* @param policy
* The {@link Policy} to render into JSON.
* @return The {@link JSONObject} representation of the {@link Policy}.
*/
@SuppressWarnings("unchecked")
public static JSONObject toJson(Policy policy) {
JSONObject policyJSON = new JSONObject();
Map<String, Object> conditions = new TreeMap<String, Object>();
conditions.put(DATE_LESS_THAN_KEY, new Long(policy.getValidUntil().getMillis()));
if (policy.getValidFrom().isPresent()) {
conditions.put(DATE_GREATER_THAN_KEY, new Long(policy.getValidFrom().get().getMillis()));
}
if (policy.getClientIpAddress().isPresent()) {
conditions.put(IP_ADDRESS_KEY, policy.getClientIpAddress().get().getHostAddress());
}
JSONObject conditionsJSON = new JSONObject();
conditionsJSON.putAll(conditions);
JSONObject statement = new JSONObject();
statement.put(RESOURCE_KEY, policy.getResource());
statement.put(CONDITION_KEY, conditions);
policyJSON.put(STATEMENT_KEY, statement);
return policyJSON;
}
/**
* Create a {@link Policy} in Json format and Base 64 encoded.
*
* @param encodedPolicy
* The String representation of the {@link Policy} in Json format and encoded into Base 64
* @return The {@link Policy} data
*/
public static Policy fromBase64EncodedPolicy(String encodedPolicy) {
String decodedPolicyString = base64Decode(encodedPolicy);
return fromJson(decodedPolicyString);
}
/**
* Create a {@link Policy} in Json format and Base 64 encoded.
*
* @param policy
* The String representation of the {@link Policy} in Json format and encoded into Base 64
* @return The {@link Policy} data
*/
public static String toBase64EncodedPolicy(Policy policy) {
return base64Encode(PolicyUtils.toJson(policy).toJSONString());
}
/**
* Get an encrypted version of a {@link Policy} to use as a signature.
*
* @param policy
* {@link Policy} that needs to be encrypted.
* @param encryptionKey
* The key to use to encrypt the {@link Policy}.
* @return An encrypted version of the {@link Policy} that is also Base64 encoded to make it safe to transmit as a
* query parameter.
* @throws Exception
* Thrown if there is a problem encrypting or encoding the {@link Policy}
*/
public static String getPolicySignature(Policy policy, String encryptionKey) throws Exception {
return SHA256Util.digest(PolicyUtils.toJson(policy).toJSONString(), encryptionKey);
}
}