/**
* Copyright 2010 Google Inc.
*
* 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.waveprotocol.box.server.waveserver;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.ProvisionException;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import org.waveprotocol.wave.crypto.SignatureException;
import org.waveprotocol.wave.crypto.SignerInfo;
import org.waveprotocol.wave.crypto.WaveSigner;
import org.waveprotocol.wave.crypto.WaveSignerFactory;
import org.waveprotocol.wave.federation.FederationSettings;
import org.waveprotocol.wave.federation.Proto.ProtocolSignature;
import org.waveprotocol.wave.federation.Proto.ProtocolWaveletDelta;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.List;
/**
* A signature handler that delegates to a wave signer to sign deltas.
*/
public class SigningSignatureHandler implements SignatureHandler {
/**
* Guice {@link Provider} for the instance of {@link SigningSignatureHandler}
*/
@Singleton
public static class SigningSignatureHandlerProvider implements Provider<SignatureHandler> {
private static final FileOpener FILE_OPENER = new FileOpener();
private String privateKey;
private List<String> certs;
private String certDomain;
private final WaveSignerFactory waveSignerFactory;
private SigningSignatureHandler signer = null;
/**
* Public constructor.
* @param privateKey file name that has the PKCS#8-PEM-encoded private key.
* @param certs list of file names that have the certificates of this signer.
* The first file name must have the signer's target certificate. The
* certificates can be DER or PEM encoded.
* @param certDomain the domain for which the certificate was issued.
* @param factory A {@link WaveSignerFactory}.
*/
@Inject
public SigningSignatureHandlerProvider(
@Named(FederationSettings.CERTIFICATE_PRIVATE_KEY) String privateKey,
@Named(FederationSettings.CERTIFICATE_FILES) List<String> certs,
@Named(FederationSettings.CERTIFICATE_DOMAIN) String certDomain,
WaveSignerFactory factory) {
this.privateKey = privateKey;
this.certs = certs;
this.certDomain = certDomain;
this.waveSignerFactory = factory;
}
@Override
public SigningSignatureHandler get() {
synchronized (this) {
if (signer == null) {
FileInputStream privateKeyStream;
try {
privateKeyStream = new FileInputStream(privateKey);
} catch (FileNotFoundException e) {
throw new ProvisionException("could not read private key", e);
}
Iterable<FileInputStream> certStreams =
Iterables.transform(certs, FILE_OPENER);
try {
WaveSigner inner = waveSignerFactory.getSigner(privateKeyStream, certStreams, certDomain);
signer = new SigningSignatureHandler(inner);
} catch (SignatureException e) {
throw new ProvisionException("could not make wave signer", e);
}
}
}
return signer;
}
// Function that turns file names into FileInputStreams
private static class FileOpener implements Function<String, FileInputStream> {
@Override
public FileInputStream apply(String filename) {
try {
return new FileInputStream(filename);
} catch (FileNotFoundException e) {
throw new ProvisionException("could not read certificates", e);
}
}
}
}
private final WaveSigner signer;
public SigningSignatureHandler(WaveSigner signer) {
this.signer = signer;
}
@Override
public String getDomain() {
return signer.getSignerInfo().getDomain();
}
public SignerInfo getSignerInfo() {
return signer.getSignerInfo();
}
@Override
public Iterable<ProtocolSignature> sign(ByteStringMessage<ProtocolWaveletDelta> delta) {
return ImmutableList.of(signer.sign(delta.getByteString().toByteArray()));
}
}