/**
* 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.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()));
}
}