UserInfoJWTView.java
/*******************************************************************************
* Copyright 2017 The MIT Internet Trust Consortium
*
* Licensed 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.mitre.openid.connect.view;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.text.ParseException;
import java.util.Date;
import java.util.Map;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.mitre.jwt.encryption.service.JWTEncryptionAndDecryptionService;
import org.mitre.jwt.signer.service.JWTSigningAndValidationService;
import org.mitre.jwt.signer.service.impl.ClientKeyCacheService;
import org.mitre.jwt.signer.service.impl.SymmetricKeyJWTValidatorCacheService;
import org.mitre.oauth2.model.ClientDetailsEntity;
import org.mitre.openid.connect.config.ConfigurationPropertiesBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.gson.JsonObject;
import com.nimbusds.jose.Algorithm;
import com.nimbusds.jose.JWEHeader;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jwt.EncryptedJWT;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
/**
* @author jricher
*
*/
@Component(UserInfoJWTView.VIEWNAME)
public class UserInfoJWTView extends UserInfoView {
public static final String CLIENT = "client";
/**
* Logger for this class
*/
private static final Logger logger = LoggerFactory.getLogger(UserInfoJWTView.class);
public static final String VIEWNAME = "userInfoJwtView";
public static final String JOSE_MEDIA_TYPE_VALUE = "application/jwt";
public static final MediaType JOSE_MEDIA_TYPE = new MediaType("application", "jwt");
@Autowired
private JWTSigningAndValidationService jwtService;
@Autowired
private ConfigurationPropertiesBean config;
@Autowired
private ClientKeyCacheService encrypters;
@Autowired
private SymmetricKeyJWTValidatorCacheService symmetricCacheService;
@Override
protected void writeOut(JsonObject json, Map<String, Object> model,
HttpServletRequest request, HttpServletResponse response) {
try {
ClientDetailsEntity client = (ClientDetailsEntity)model.get(CLIENT);
// use the parser to import the user claims into the object
StringWriter writer = new StringWriter();
gson.toJson(json, writer);
response.setContentType(JOSE_MEDIA_TYPE_VALUE);
JWTClaimsSet claims = new JWTClaimsSet.Builder(JWTClaimsSet.parse(writer.toString()))
.audience(Lists.newArrayList(client.getClientId()))
.issuer(config.getIssuer())
.issueTime(new Date())
.jwtID(UUID.randomUUID().toString()) // set a random NONCE in the middle of it
.build();
if (client.getUserInfoEncryptedResponseAlg() != null && !client.getUserInfoEncryptedResponseAlg().equals(Algorithm.NONE)
&& client.getUserInfoEncryptedResponseEnc() != null && !client.getUserInfoEncryptedResponseEnc().equals(Algorithm.NONE)
&& (!Strings.isNullOrEmpty(client.getJwksUri()) || client.getJwks() != null)) {
// encrypt it to the client's key
JWTEncryptionAndDecryptionService encrypter = encrypters.getEncrypter(client);
if (encrypter != null) {
EncryptedJWT encrypted = new EncryptedJWT(new JWEHeader(client.getUserInfoEncryptedResponseAlg(), client.getUserInfoEncryptedResponseEnc()), claims);
encrypter.encryptJwt(encrypted);
Writer out = response.getWriter();
out.write(encrypted.serialize());
} else {
logger.error("Couldn't find encrypter for client: " + client.getClientId());
}
} else {
JWSAlgorithm signingAlg = jwtService.getDefaultSigningAlgorithm(); // default to the server's preference
if (client.getUserInfoSignedResponseAlg() != null) {
signingAlg = client.getUserInfoSignedResponseAlg(); // override with the client's preference if available
}
JWSHeader header = new JWSHeader(signingAlg, null, null, null, null, null, null, null, null, null,
jwtService.getDefaultSignerKeyId(),
null, null);
SignedJWT signed = new SignedJWT(header, claims);
if (signingAlg.equals(JWSAlgorithm.HS256)
|| signingAlg.equals(JWSAlgorithm.HS384)
|| signingAlg.equals(JWSAlgorithm.HS512)) {
// sign it with the client's secret
JWTSigningAndValidationService signer = symmetricCacheService.getSymmetricValidtor(client);
signer.signJwt(signed);
} else {
// sign it with the server's key
jwtService.signJwt(signed);
}
Writer out = response.getWriter();
out.write(signed.serialize());
}
} catch (IOException e) {
logger.error("IO Exception in UserInfoJwtView", e);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}