package org.oregami.dropwizard;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.github.toastshaman.dropwizard.auth.jwt.JWTAuthFactory;
import com.github.toastshaman.dropwizard.auth.jwt.JsonWebTokenParser;
import com.github.toastshaman.dropwizard.auth.jwt.JsonWebTokenValidator;
import com.github.toastshaman.dropwizard.auth.jwt.exceptions.TokenExpiredException;
import com.github.toastshaman.dropwizard.auth.jwt.hmac.HmacSHA512Verifier;
import com.github.toastshaman.dropwizard.auth.jwt.model.JsonWebToken;
import com.github.toastshaman.dropwizard.auth.jwt.parser.DefaultJsonWebTokenParser;
import com.github.toastshaman.dropwizard.auth.jwt.validator.ExpiryValidator;
import com.google.common.base.Optional;
import com.google.inject.persist.PersistFilter;
import com.google.inject.persist.jpa.JpaPersistModule;
import com.hubspot.dropwizard.guice.GuiceBundle;
import io.dropwizard.Application;
import io.dropwizard.auth.AuthFactory;
import io.dropwizard.auth.AuthenticationException;
import io.dropwizard.auth.Authenticator;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;
import org.eclipse.jetty.servlets.CrossOriginFilter;
import org.glassfish.hk2.utilities.Binder;
import org.joda.time.Duration;
import org.oregami.data.DatabaseFiller;
import org.oregami.entities.user.User;
import org.oregami.resources.*;
import org.oregami.util.AuthHelper;
import org.oregami.util.MailHelper;
import org.oregami.util.StartHelper;
import org.oregami.util.WebsiteHelper;
import javax.servlet.DispatcherType;
import javax.servlet.FilterRegistration.Dynamic;
import java.util.EnumSet;
import java.util.Properties;
public class OregamiApplication extends Application<OregamiConfiguration> {
private GuiceBundle<OregamiConfiguration> guiceBundle;
public static void main(String[] args) throws Exception {
for (int i=0; i<args.length; i++) {
if (args[i].endsWith(".yml")) {
StartHelper.setConfigFilename(args[i]);
}
}
new OregamiApplication().run(args);
}
@Override
public void initialize(Bootstrap<OregamiConfiguration> bootstrap) {
OregamiConfiguration configuration = StartHelper.createConfiguration(StartHelper.getConfigFilename());
Properties jpaProperties = StartHelper.createPropertiesFromConfiguration(configuration);
JpaPersistModule jpaPersistModule = new JpaPersistModule(configuration.getDatabaseConfiguration().getJpaUnit());
jpaPersistModule.properties(jpaProperties);
guiceBundle = GuiceBundle.<OregamiConfiguration>newBuilder()
.addModule(new OregamiGuiceModule())
.addModule(jpaPersistModule)
.enableAutoConfig("org.oregami")
.setConfigClass(OregamiConfiguration.class)
.build();
bootstrap.addBundle(guiceBundle);
SimpleModule module = new SimpleModule();
//module.addSerializer(LocalDateTime.class, new CustomLocalDateTimeSerializer());
//module.addSerializer(LocalDate.class, new CustomLocalDateSerializer());
bootstrap.getObjectMapper().registerModule(module);
}
@Override
public void run(OregamiConfiguration config, Environment environment)
throws Exception {
environment.servlets().addFilter("persistFilter", guiceBundle.getInjector().getInstance(PersistFilter.class)).addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
StartHelper.init(StartHelper.getConfigFilename());
DatabaseFiller databaseFiller = StartHelper.getInjector().getInstance(DatabaseFiller.class);
if (config.isInitBaseLists()) {
databaseFiller.initBaseLists();
}
if (config.isInitGames()) {
databaseFiller.initGameData();
}
databaseFiller.initDemoUser();
WebsiteHelper.init(config.getPhantomJSConfiguration().getPhantomjsCommandLocation(), config.getPhantomJSConfiguration().getRasterizeJSFileLocation());
MailHelper.init(config.getMailConfiguration());
Dynamic filter = environment.servlets().addFilter("CORS", CrossOriginFilter.class);
filter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "/*");
filter.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "GET,PUT,POST,DELETE,OPTIONS");
filter.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, "*");
filter.setInitParameter(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER, "*");
filter.setInitParameter(CrossOriginFilter.EXPOSED_HEADERS_PARAM, "Content-Type,Authorization,X-Requested-With,Content-Length,Accept,Origin,Location");
filter.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM, "Content-Type,Authorization,X-Requested-With,Content-Length,Accept,Origin,Location");
filter.setInitParameter(CrossOriginFilter.ALLOW_CREDENTIALS_PARAM, "true");
//
// filter.setInitParameter("allow", "GET,PUT,POST,DELETE,OPTIONS");
// filter.setInitParameter("preflightMaxAge", "5184000"); // 2 months
environment.jersey().register(guiceBundle.getInjector().getInstance(GamesResource.class));
environment.jersey().register(guiceBundle.getInjector().getInstance(HomeResource.class));
environment.jersey().register(guiceBundle.getInjector().getInstance(AdminResource.class));
environment.jersey().register(guiceBundle.getInjector().getInstance(PublicationFranchiseResource.class));
environment.jersey().register(guiceBundle.getInjector().getInstance(WebsiteResource.class));
environment.jersey().register(guiceBundle.getInjector().getInstance(UserResource.class));
environment.jersey().register(guiceBundle.getInjector().getInstance(ScriptResource.class));
environment.jersey().register(guiceBundle.getInjector().getInstance(TransliteratedStringResource.class));
environment.jersey().register(guiceBundle.getInjector().getInstance(HardwarePlatformResource.class));
environment.jersey().register(createAuthProvider());
environment.jersey().register(guiceBundle.getInjector().getInstance(JWTResource.class));
}
private static class ExampleAuthenticator implements Authenticator<JsonWebToken, User> {
@Override
public Optional<User> authenticate(JsonWebToken token) throws AuthenticationException {
final JsonWebTokenValidator expiryValidator = new ExpiryValidator(Duration.standardSeconds(1));
//final JsonWebTokenValidator expiryValidator = new ExpiryValidator();
// Provide your own implementation to lookup users based on the principal attribute in the
// JWT Token. E.g.: lookup users from a database etc.
// This method will be called once the token's signature has been verified
// In case you want to verify different parts of the token you can do that here.
// E.g.: Verifying that the provided token has not expired.
try {
expiryValidator.validate(token);
} catch (TokenExpiredException e) {
throw new AuthenticationException(e.getMessage(), e);
}
final AuthHelper authHelper = StartHelper.getInstance(AuthHelper.class);
//check if username is present:
Object tokenUsername = token.claim().getParameter("username");
if (tokenUsername != null) {
return Optional.of(authHelper.getUserByUsername(tokenUsername.toString()));
}
return Optional.absent();
}
}
private Binder createAuthProvider() {
JsonWebTokenParser tokenParser = new DefaultJsonWebTokenParser();
final HmacSHA512Verifier tokenVerifier = new HmacSHA512Verifier(AuthHelper.authKey);
Binder authProvider = AuthFactory.binder(new JWTAuthFactory<>(new ExampleAuthenticator(), "realm", User.class, tokenVerifier, tokenParser));
return authProvider;
}
}