/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache 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://www.apache.org/licenses/LICENSE-2.0
*
* 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.apache.cxf.rs.security.jose.jws;
import java.util.Collections;
import java.util.logging.Logger;
import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.common.util.Base64UrlUtility;
import org.apache.cxf.common.util.StringUtils;
import org.apache.cxf.jaxrs.json.basic.JsonMapObjectReaderWriter;
import org.apache.cxf.jaxrs.json.basic.JsonObject;
import org.apache.cxf.rs.security.jose.common.JoseConstants;
import org.apache.cxf.rs.security.jose.common.JoseUtils;
import org.apache.cxf.rs.security.jose.jwk.JsonWebKey;
public class JwsJsonSignatureEntry implements JsonObject {
protected static final Logger LOG = LogUtils.getL7dLogger(JwsJsonSignatureEntry.class);
private String jwsPayload;
private String encodedProtectedHeader;
private String encodedSignature;
private JwsHeaders protectedHeader;
private JwsHeaders unprotectedHeader;
private JwsHeaders unionHeaders;
private JsonMapObjectReaderWriter writer = new JsonMapObjectReaderWriter();
public JwsJsonSignatureEntry(String jwsPayload,
String encodedProtectedHeader,
String encodedSignature,
JwsHeaders unprotectedHeader) {
if (encodedProtectedHeader == null && unprotectedHeader == null || encodedSignature == null) {
LOG.warning("Invalid Signature entry");
throw new JwsException(JwsException.Error.INVALID_JSON_JWS);
}
this.jwsPayload = jwsPayload;
this.encodedProtectedHeader = encodedProtectedHeader;
this.encodedSignature = encodedSignature;
this.unprotectedHeader = unprotectedHeader;
if (encodedProtectedHeader != null) {
this.protectedHeader = new JwsHeaders(writer.fromJson(JoseUtils.decodeToString(encodedProtectedHeader)));
}
prepare();
}
private void prepare() {
unionHeaders = new JwsHeaders();
if (protectedHeader != null) {
unionHeaders.asMap().putAll(protectedHeader.asMap());
}
if (unprotectedHeader != null) {
if (!Collections.disjoint(unionHeaders.asMap().keySet(),
unprotectedHeader.asMap().keySet())) {
LOG.warning("Protected and unprotected headers have duplicate values");
throw new JwsException(JwsException.Error.INVALID_JSON_JWS);
}
unionHeaders.asMap().putAll(unprotectedHeader.asMap());
}
}
public String getJwsPayload() {
return jwsPayload;
}
public String getDecodedJwsPayload() {
if (protectedHeader == null || !JwsUtils.isPayloadUnencoded(protectedHeader)) {
return JoseUtils.decodeToString(jwsPayload);
} else {
return jwsPayload;
}
}
public byte[] getDecodedJwsPayloadBytes() {
return StringUtils.toBytesUTF8(getDecodedJwsPayload());
}
public String getEncodedProtectedHeader() {
return encodedProtectedHeader;
}
public JwsHeaders getProtectedHeader() {
return protectedHeader;
}
public JwsHeaders getUnprotectedHeader() {
return unprotectedHeader;
}
public JwsHeaders getUnionHeader() {
return unionHeaders;
}
public String getEncodedSignature() {
return encodedSignature;
}
public byte[] getDecodedSignature() {
return JoseUtils.decode(getEncodedSignature());
}
public String getUnsignedSequence() {
if (getEncodedProtectedHeader() != null) {
return getEncodedProtectedHeader() + "." + getJwsPayload();
} else {
return "." + getJwsPayload();
}
}
public String getKeyId() {
return getUnionHeader().getKeyId();
}
public boolean verifySignatureWith(JwsSignatureVerifier validator) {
try {
if (validator.verify(getUnionHeader(),
getUnsignedSequence(),
getDecodedSignature())) {
return true;
}
} catch (JwsException ex) {
// ignore
}
LOG.warning("Invalid Signature Entry");
return false;
}
public boolean verifySignatureWith(JsonWebKey key) {
return verifySignatureWith(JwsUtils.getSignatureVerifier(key));
}
public boolean validateCriticalHeaders() {
if (this.getUnprotectedHeader().getHeader(JoseConstants.HEADER_CRITICAL) != null) {
return false;
}
return JwsUtils.validateCriticalHeaders(getUnionHeader());
}
public String toJson() {
return toJson(false);
}
public String toJson(boolean flattenedMode) {
StringBuilder sb = new StringBuilder();
if (!flattenedMode) {
sb.append("{");
}
if (protectedHeader != null) {
sb.append("\"protected\":\"" + Base64UrlUtility.encode(writer.toJson(protectedHeader)) + "\"");
}
if (unprotectedHeader != null) {
if (protectedHeader != null) {
sb.append(",");
}
sb.append("\"header\":" + writer.toJson(unprotectedHeader));
}
sb.append(",");
sb.append("\"signature\":\"" + encodedSignature + "\"");
if (!flattenedMode) {
sb.append("}");
}
return sb.toString();
}
}