001 /** 002 * Copyright 2005-2013 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.kuali.rice.ksb.security; 017 018 import java.io.ByteArrayInputStream; 019 import java.io.IOException; 020 import java.security.Signature; 021 import java.security.cert.CertificateFactory; 022 023 import javax.servlet.ServletInputStream; 024 import javax.servlet.http.HttpServletRequest; 025 import javax.servlet.http.HttpServletRequestWrapper; 026 027 import org.apache.commons.codec.binary.Base64; 028 import org.apache.commons.lang.StringUtils; 029 import org.kuali.rice.ksb.service.KSBServiceLocator; 030 import org.kuali.rice.ksb.util.KSBConstants; 031 032 /** 033 * An HttpServletRequestWrapper which will wraps the underlying request's InputStream in a 034 * SignatureVerifyingInputStream which will verify the digital signature of the request after 035 * all of the data has been read from the input stream. 036 * 037 * @author Kuali Rice Team (rice.collab@kuali.org) 038 */ 039 public class SignatureVerifyingRequestWrapper extends HttpServletRequestWrapper { 040 041 private byte[] digitalSignature; 042 private Signature signature; 043 044 public SignatureVerifyingRequestWrapper(HttpServletRequest request) { 045 super(request); 046 String encodedSignature = request.getHeader(KSBConstants.DIGITAL_SIGNATURE_HEADER); 047 if (StringUtils.isEmpty(encodedSignature)) { 048 throw new RuntimeException("A digital signature was required on the request but none was found."); 049 } 050 String verificationAlias = request.getHeader(KSBConstants.KEYSTORE_ALIAS_HEADER); 051 String encodedCertificate = request.getHeader(KSBConstants.KEYSTORE_CERTIFICATE_HEADER); 052 if ( (StringUtils.isEmpty(verificationAlias)) && (StringUtils.isEmpty(encodedCertificate)) ) { 053 throw new RuntimeException("A verification alias or certificate was required on the request but neither was found."); 054 } 055 try { 056 this.digitalSignature = Base64.decodeBase64(encodedSignature.getBytes("UTF-8")); 057 if (StringUtils.isNotBlank(encodedCertificate)) { 058 byte[] certificate = Base64.decodeBase64(encodedCertificate.getBytes("UTF-8")); 059 CertificateFactory cf = CertificateFactory.getInstance("X.509"); 060 this.signature = KSBServiceLocator.getDigitalSignatureService().getSignatureForVerification(cf.generateCertificate(new ByteArrayInputStream(certificate))); 061 } else if (StringUtils.isNotBlank(verificationAlias)) { 062 this.signature = KSBServiceLocator.getDigitalSignatureService().getSignatureForVerification(verificationAlias); 063 } 064 } catch (Exception e) { 065 throw new RuntimeException("Failed to initialize digital signature verification.", e); 066 } 067 } 068 069 @Override 070 public ServletInputStream getInputStream() throws IOException { 071 return new SignatureVerifyingInputStream(this.digitalSignature, this.signature, super.getInputStream()); 072 } 073 074 }