nu.yona.server.AppServiceApplication.java Source code

Java tutorial

Introduction

Here is the source code for nu.yona.server.AppServiceApplication.java

Source

/*******************************************************************************
 * Copyright (c) 2015, 2018 Stichting Yona Foundation This Source Code Form is subject to the terms of the Mozilla Public License,
 * v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
 *******************************************************************************/
package nu.yona.server;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Enumeration;

import javax.annotation.PostConstruct;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.spring4.SpringTemplateEngine;
import org.thymeleaf.templateresolver.FileTemplateResolver;

import nu.yona.server.exceptions.ConfigurationException;
import nu.yona.server.exceptions.YonaException;
import nu.yona.server.properties.PropertyInitializer;
import nu.yona.server.properties.YonaProperties;

@SpringBootApplication
@EnableCaching
public class AppServiceApplication {
    private static final Logger logger = LoggerFactory.getLogger(AppServiceApplication.class);
    @Autowired
    private YonaProperties yonaProperties;

    public static void main(String[] args) {
        PropertyInitializer.initializePropertiesFromEnvironment();
        SpringApplication.run(AppServiceApplication.class, args);
    }

    @PostConstruct
    public void initialize() {
        Security.addProvider(new BouncyCastleProvider());
    }

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/swagger/swagger-spec.yaml");
                if (yonaProperties.getSecurity().isCorsAllowed()) {
                    // Enable CORS for the other resources, to allow testing the API through Swagger UI.
                    registry.addMapping("/**").allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE");
                }
            }
        };
    }

    @Bean
    @Qualifier("appleMobileConfigSigningKeyStore")
    public KeyStore appleMobileConfigSigningKeyStore() {
        String fileName = yonaProperties.getAppleMobileConfig().getSigningKeyStoreFile();
        logger.info("Loading Apple mobile config signing key store from {}", fileName);
        try (InputStream inStream = new FileInputStream(fileName)) {
            KeyStore keyStore = java.security.KeyStore.getInstance("PKCS12");
            keyStore.load(inStream,
                    yonaProperties.getAppleMobileConfig().getSigningKeyStorePassword().toCharArray());
            assertKeyStoreContent(keyStore);
            return keyStore;
        } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException e) {
            throw YonaException.unexpected(e);
        }
    }

    private void assertKeyStoreContent(KeyStore keyStore) {
        try {
            String alias = yonaProperties.getAppleMobileConfig().getSigningAlias();
            if (!keyStore.isKeyEntry(alias)) {
                logAliases(keyStore);
                throw ConfigurationException.missingKeyInKeyStore(alias);
            }
        } catch (KeyStoreException e) {
            throw YonaException.unexpected(e);
        }
    }

    private void logAliases(KeyStore keyStore) {
        try {
            Enumeration<String> aliasEnum = keyStore.aliases();
            while (aliasEnum.hasMoreElements()) {
                logger.info("Key store contains alias '{}'", aliasEnum.nextElement());
            }
        } catch (KeyStoreException e) {
            throw YonaException.unexpected(e);
        }
    }

    @Bean
    @Qualifier("appleMobileConfigSigningCertificate")
    public X509Certificate appleMobileConfigSigningCertificate(KeyStore keyStore) {
        try {
            return (X509Certificate) keyStore
                    .getCertificate(yonaProperties.getAppleMobileConfig().getSigningAlias());
        } catch (KeyStoreException e) {
            throw YonaException.unexpected(e);
        }
    }

    @Bean
    @Qualifier("appleMobileConfigSignerKey")
    public PrivateKey appleMobileConfigSignerKey(KeyStore keyStore) {
        try {
            return (PrivateKey) keyStore.getKey(yonaProperties.getAppleMobileConfig().getSigningAlias(),
                    yonaProperties.getAppleMobileConfig().getSigningKeyStorePassword().toCharArray());
        } catch (UnrecoverableKeyException | KeyStoreException | NoSuchAlgorithmException e) {
            throw YonaException.unexpected(e);
        }
    }

    @Bean
    @Qualifier("appleMobileConfigCaCertificate")
    public X509Certificate appleMobileConfigCaCertificate() {
        return loadCertificateFromFile(yonaProperties.getAppleMobileConfig().getCaCertificateFile(),
                "Apple mobile config CA");
    }

    @Bean
    @Qualifier("appleMobileConfigTemplateEngine")
    public TemplateEngine appleMobileConfigTemplateEngine() {
        String appleMobileConfigFile = yonaProperties.getAppleMobileConfig().getAppleMobileConfigFile();
        FileTemplateResolver templateResolver = new FileTemplateResolver();
        templateResolver.setPrefix(new File(appleMobileConfigFile).getParent() + File.separator);
        templateResolver.setSuffix(appleMobileConfigFile.substring(appleMobileConfigFile.lastIndexOf('.')));

        TemplateEngine templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(templateResolver);
        return templateEngine;
    }

    @Bean
    @Qualifier("sslRootCertificate")
    public X509Certificate sslRootCertificate() {
        return loadCertificateFromFile(yonaProperties.getSecurity().getSslRootCertFile(), "SSL root");
    }

    private X509Certificate loadCertificateFromFile(String fileName, String description) {
        logger.info("Loading {} certificate from {}", description, fileName);
        try (InputStream inStream = new FileInputStream(fileName)) {
            return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(inStream);
        } catch (IOException | CertificateException e) {
            throw YonaException.unexpected(e);
        }
    }
}