/**
* 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.oauth2.client;
import java.util.List;
import java.util.Map;
import javax.ws.rs.core.MultivaluedMap;
import org.apache.cxf.common.util.StringUtils;
import org.apache.cxf.helpers.CastUtils;
import org.apache.cxf.jaxrs.ext.MessageContext;
import org.apache.cxf.jaxrs.impl.MetadataMap;
import org.apache.cxf.jaxrs.json.basic.JsonMapObjectReaderWriter;
import org.apache.cxf.rs.security.jose.jwe.JweDecryptionProvider;
import org.apache.cxf.rs.security.jose.jwe.JweEncryptionProvider;
import org.apache.cxf.rs.security.jose.jwe.JweUtils;
import org.apache.cxf.rs.security.jose.jws.JwsCompactConsumer;
import org.apache.cxf.rs.security.jose.jws.JwsCompactProducer;
import org.apache.cxf.rs.security.jose.jws.JwsSignatureProvider;
import org.apache.cxf.rs.security.jose.jws.JwsSignatureVerifier;
import org.apache.cxf.rs.security.jose.jws.JwsUtils;
import org.apache.cxf.rs.security.jose.jws.NoneJwsSignatureProvider;
import org.apache.cxf.rs.security.oauth2.provider.OAuthServiceException;
import org.apache.cxf.rs.security.oauth2.utils.OAuthConstants;
import org.apache.cxf.rs.security.oauth2.utils.OAuthUtils;
public class JoseClientCodeStateManager implements ClientCodeStateManager {
private JwsSignatureProvider sigProvider;
private JweEncryptionProvider encryptionProvider;
private JweDecryptionProvider decryptionProvider;
private JwsSignatureVerifier signatureVerifier;
private JsonMapObjectReaderWriter jsonp = new JsonMapObjectReaderWriter();
private boolean generateNonce;
private boolean storeInSession;
@Override
public MultivaluedMap<String, String> toRedirectState(MessageContext mc,
MultivaluedMap<String, String> requestState) {
JweEncryptionProvider theEncryptionProvider = getInitializedEncryptionProvider();
JwsSignatureProvider theSigProvider = getInitializedSigProvider(theEncryptionProvider);
if (theEncryptionProvider == null && theSigProvider == null) {
throw new OAuthServiceException("The state can not be protected");
}
MultivaluedMap<String, String> redirectMap = new MetadataMap<String, String>();
if (generateNonce && theSigProvider != null) {
JwsCompactProducer nonceProducer = new JwsCompactProducer(OAuthUtils.generateRandomTokenKey());
String nonceParam = nonceProducer.signWith(theSigProvider);
requestState.putSingle(OAuthConstants.NONCE, nonceParam);
redirectMap.putSingle(OAuthConstants.NONCE, nonceParam);
}
Map<String, Object> stateMap = CastUtils.cast((Map<?, ?>)requestState);
String json = jsonp.toJson(stateMap);
String stateParam = null;
if (theSigProvider != null) {
JwsCompactProducer stateProducer = new JwsCompactProducer(json);
stateParam = stateProducer.signWith(theSigProvider);
}
if (theEncryptionProvider != null) {
stateParam = theEncryptionProvider.encrypt(StringUtils.toBytesUTF8(stateParam), null);
}
if (storeInSession) {
String sessionStateAttribute = OAuthUtils.generateRandomTokenKey();
OAuthUtils.setSessionToken(mc, stateParam, sessionStateAttribute, 0);
stateParam = sessionStateAttribute;
}
redirectMap.putSingle(OAuthConstants.STATE, stateParam);
return redirectMap;
}
@Override
public MultivaluedMap<String, String> fromRedirectState(MessageContext mc,
MultivaluedMap<String, String> redirectState) {
String stateParam = redirectState.getFirst(OAuthConstants.STATE);
if (storeInSession) {
stateParam = OAuthUtils.getSessionToken(mc, stateParam);
}
JweDecryptionProvider jwe = getInitializedDecryptionProvider();
if (jwe != null) {
stateParam = jwe.decrypt(stateParam).getContentText();
}
JwsCompactConsumer jws = new JwsCompactConsumer(stateParam);
JwsSignatureVerifier theSigVerifier = getInitializedSigVerifier();
if (!jws.verifySignatureWith(theSigVerifier)) {
throw new SecurityException();
}
String json = jws.getUnsignedEncodedSequence();
//CHECKSTYLE:OFF
Map<String, List<String>> map = CastUtils.cast((Map<?, ?>)jsonp.fromJson(json));
return (MultivaluedMap<String, String>)map; //NOPMD
//CHECKSTYLE:ON
}
public void setSignatureProvider(JwsSignatureProvider signatureProvider) {
this.sigProvider = signatureProvider;
}
protected JwsSignatureProvider getInitializedSigProvider(JweEncryptionProvider theEncryptionProvider) {
if (sigProvider != null) {
return sigProvider;
}
JwsSignatureProvider theSigProvider = JwsUtils.loadSignatureProvider(false);
if (theSigProvider == null && theEncryptionProvider != null) {
theSigProvider = new NoneJwsSignatureProvider();
}
return theSigProvider;
}
public void setDecryptionProvider(JweDecryptionProvider decProvider) {
this.decryptionProvider = decProvider;
}
protected JweDecryptionProvider getInitializedDecryptionProvider() {
if (decryptionProvider != null) {
return decryptionProvider;
}
return JweUtils.loadDecryptionProvider(false);
}
public void setSignatureVerifier(JwsSignatureVerifier signatureVerifier) {
this.signatureVerifier = signatureVerifier;
}
protected JwsSignatureVerifier getInitializedSigVerifier() {
if (signatureVerifier != null) {
return signatureVerifier;
}
return JwsUtils.loadSignatureVerifier(false);
}
public void setEncryptionProvider(JweEncryptionProvider encProvider) {
this.encryptionProvider = encProvider;
}
protected JweEncryptionProvider getInitializedEncryptionProvider() {
if (encryptionProvider != null) {
return encryptionProvider;
}
return JweUtils.loadEncryptionProvider(false);
}
public void setGenerateNonce(boolean generateNonce) {
this.generateNonce = generateNonce;
}
public void setStoreInSession(boolean storeInSession) {
this.storeInSession = storeInSession;
}
}