/**
* 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.typesafe.config.Config;
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.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;
/**
* @param factory A {@link WaveSignerFactory}.
* @param config the configuration.
*/
@Inject
public SigningSignatureHandlerProvider(WaveSignerFactory factory, Config config) {
this.privateKey = config.getString("federation.certificate_private_key");
this.certs = config.getStringList("federation.certificate_files");
this.certDomain = config.getString("federation.certificate_domain");
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()));
}
}