blob: a761a3e580c519a40c9e6315d766991e2b237f50 [file] [log] [blame]
/*
* 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.oltu.jose.jws;
import org.apache.oltu.commons.encodedtoken.TokenDecoder;
import org.apache.oltu.commons.json.CustomizableBuilder;
import org.apache.oltu.jose.jws.io.JWSHeaderWriter;
import org.apache.oltu.jose.jws.signature.SignatureMethod;
import org.apache.oltu.jose.jws.signature.SigningKey;
import org.apache.oltu.jose.jws.signature.VerifyingKey;
public class JWS {
/**
* The raw JWS String
*/
private String rawString;
/**
* The JWS Header.
*/
private final Header header;
/**
* The JWS Payload.
*/
private final String payload;
/**
* The JWS Signature.
*/
private final String signature;
JWS(Header header, String payload, String signature) {
this(null, header, payload, signature);
}
JWS(String rawString, Header header, String payload, String signature) {
this.rawString = rawString;
this.header = header;
this.payload = payload;
this.signature = signature;
}
public Header getHeader() {
return header;
}
public String getPayload() {
return payload;
}
public String getSignature() {
return signature;
}
public <SK extends SigningKey, VK extends VerifyingKey> boolean acceptAlgorithm(SignatureMethod<SK, VK> method) {
if (method == null) {
throw new IllegalArgumentException("A signature method is required in order to verify the signature.");
}
if (header == null || header.getAlgorithm() == null) {
throw new IllegalStateException("JWS token must have a valid JSON header with specified algorithm.");
}
return header.getAlgorithm().equalsIgnoreCase(method.getAlgorithm());
}
public <SK extends SigningKey, VK extends VerifyingKey> boolean validate(SignatureMethod<SK, VK> method,
VK verifyingKey) {
if (!acceptAlgorithm(method)) {
throw new IllegalArgumentException("Impossible to verify current JWS signature with algorithm '"
+ method.getAlgorithm()
+ "', JWS header specifies message has been signed with '"
+ header.getAlgorithm()
+ "' algorithm.");
}
if (verifyingKey == null) {
throw new IllegalArgumentException("A verifying key is required in order to verify the signature.");
}
if (payload == null) {
throw new IllegalStateException("JWS token must have a payload.");
}
if (signature == null) {
throw new IllegalStateException("JWS token must have a signature to be verified.");
}
if (rawString == null) {
return method.verify(signature, TokenDecoder.base64Encode(new JWSHeaderWriter().write(header)), TokenDecoder.base64Encode(payload), verifyingKey);
} else {
String jwt[] = rawString.split("\\.");
return method.verify(jwt[2], jwt[0], jwt[1], verifyingKey);
}
}
public static final class Builder extends CustomizableBuilder<JWS> {
public Builder(){}
public Builder(String rawString) {
this.rawString = rawString;
}
/**
* The raw JWS String
*/
private String rawString;
/**
* The {@code alg} JWS Header parameter.
*/
private String algorithm;
/**
* The {@code jku} JWS Header parameter.
*/
private String jwkSetUrl;
/**
* The {@code jwk} JWS Header parameter.
*/
private String jsonWebKey;
/**
* The {@code x5u} JWS Header parameter.
*/
private String x509url;
/**
* The {@code x5t} JWS Header parameter.
*/
private String x509CertificateThumbprint;
/**
* The {@code x5c} JWS Header parameter.
*/
private String x509CertificateChain;
/**
* The {@code kid} JWS Header parameter.
*/
private String keyId;
/**
* The {@code typ} JWS Header parameter.
*/
private String type;
/**
* The {@code cty} JWS Header parameter.
*/
private String contentType;
/**
* The {@code crit} JWS Header parameter.
*/
private String[] critical;
/**
* The JWS Payload.
*/
private String payload;
/**
* The JWS Signature.
*/
private String signature;
public Builder setAlgorithm(String algorithm) {
this.algorithm = algorithm;
return this;
}
public Builder setJwkSetUrl(String jwkSetUrl) {
this.jwkSetUrl = jwkSetUrl;
return this;
}
public Builder setJsonWebKey(String jsonWebKey) {
this.jsonWebKey = jsonWebKey;
return this;
}
public Builder setX509url(String x509url) {
this.x509url = x509url;
return this;
}
public Builder setX509CertificateThumbprint(String x509CertificateThumbprint) {
this.x509CertificateThumbprint = x509CertificateThumbprint;
return this;
}
public Builder setX509CertificateChain(String x509CertificateChain) {
this.x509CertificateChain = x509CertificateChain;
return this;
}
public Builder setKeyId(String keyId) {
this.keyId = keyId;
return this;
}
public Builder setType(String type) {
this.type = type;
return this;
}
public Builder setContentType(String contentType) {
this.contentType = contentType;
return this;
}
public Builder setCritical(String[] critical) {
this.critical = critical;
return this;
}
public Builder setPayload(String payload) {
this.payload = payload;
return this;
}
public Builder setSignature(String signature) {
this.signature = signature;
return this;
}
public <SK extends SigningKey, VK extends VerifyingKey> Builder sign(SignatureMethod<SK, VK> method,
SK signingKey) {
if (method == null) {
throw new IllegalArgumentException("A signature method is required in order to calculate the signature.");
}
if (signingKey == null) {
throw new IllegalArgumentException("A signing key is required in order to calculate the signature.");
}
if (payload == null) {
throw new IllegalStateException("Payload needs to be set in order to sign the current JWT");
}
setAlgorithm(method.getAlgorithm());
String header = new JWSHeaderWriter().write(new Header(algorithm,
jwkSetUrl,
jsonWebKey,
x509url,
x509CertificateThumbprint,
x509CertificateChain,
keyId, type,
contentType,
critical,
getCustomFields()));
return setSignature(method.calculate(TokenDecoder.base64Encode(header), TokenDecoder.base64Encode(payload), signingKey));
}
public JWS build() {
return new JWS(rawString, new Header(algorithm,
jwkSetUrl,
jsonWebKey,
x509url,
x509CertificateThumbprint,
x509CertificateChain,
keyId, type,
contentType,
critical,
getCustomFields()),
payload,
signature);
}
}
}