/**
* diqube: Distributed Query Base.
*
* Copyright (C) 2015 Bastian Gloeckle
*
* This file is part of diqube.
*
* diqube is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diqube.ticket;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import org.diqube.context.Profiles;
import org.diqube.remote.query.TicketInfoUtil;
import org.diqube.thrift.base.thrift.Ticket;
import org.diqube.thrift.base.thrift.TicketClaim;
import org.diqube.thrift.base.util.RUuidUtil;
import org.diqube.ticket.TicketRsaKeyFileProvider.IOExceptionSupplier;
import org.diqube.util.Triple;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
/**
*
* @author Bastian Gloeckle
*/
public class TicketValidityServiceTest {
private static final Triple<String, IOExceptionSupplier<InputStream>, String> PRIVATE_PLAIN =
new Triple<>("private.plain", () -> TicketValidityServiceTest.class
.getResourceAsStream("/" + TicketValidityServiceTest.class.getSimpleName() + "/private.plain.pem"), null);
private AnnotationConfigApplicationContext dataContext;
private TicketSignatureService ticketSignatureService;
private TicketValidityService ticketValidityService;
@BeforeMethod
public void before() {
}
@AfterMethod
public void after() {
dataContext.close();
dataContext = null;
ticketSignatureService = null;
ticketValidityService = null;
}
@Test
public void invalidated() {
synchronized (TestTicketRsaKeyFileProvider.class) {
TestTicketRsaKeyFileProvider.clean();
TestTicketRsaKeyFileProvider.files.add(PRIVATE_PLAIN);
TestTicketRsaKeyFileProvider.isFilesWithPrivateKeyAreRequired = true;
startNewContext(0);
// GIVEN
Ticket t = new Ticket();
t.setClaim(new TicketClaim());
t.getClaim().setTicketId(RUuidUtil.toRUuid(UUID.randomUUID()));
t.getClaim().setUsername("abc");
t.getClaim().setValidUntil(123);
t.getClaim().setIsSuperUser(false);
ticketSignatureService.signTicket(t);
// WHEN
ticketValidityService.markTicketAsInvalid(TicketInfoUtil.fromTicket(t));
boolean isValid = ticketValidityService.isTicketValid(t);
// THEN
Assert.assertFalse(isValid, "Ticket should NOT be valid.");
}
}
@Test
public void tooLate() {
synchronized (TestTicketRsaKeyFileProvider.class) {
TestTicketRsaKeyFileProvider.clean();
TestTicketRsaKeyFileProvider.files.add(PRIVATE_PLAIN);
TestTicketRsaKeyFileProvider.isFilesWithPrivateKeyAreRequired = true;
startNewContext(500); // now is "500"
// GIVEN
Ticket t = new Ticket();
t.setClaim(new TicketClaim());
t.getClaim().setTicketId(RUuidUtil.toRUuid(UUID.randomUUID()));
t.getClaim().setUsername("abc");
t.getClaim().setValidUntil(123);
t.getClaim().setIsSuperUser(false);
ticketSignatureService.signTicket(t);
// WHEN
boolean isValid = ticketValidityService.isTicketValid(t);
// THEN
Assert.assertFalse(isValid, "Ticket should NOT be valid.");
}
}
@Test
public void tampered() {
synchronized (TestTicketRsaKeyFileProvider.class) {
TestTicketRsaKeyFileProvider.clean();
TestTicketRsaKeyFileProvider.files.add(PRIVATE_PLAIN);
TestTicketRsaKeyFileProvider.isFilesWithPrivateKeyAreRequired = true;
startNewContext(0);
// GIVEN
Ticket t = new Ticket();
t.setClaim(new TicketClaim());
t.getClaim().setTicketId(RUuidUtil.toRUuid(UUID.randomUUID()));
t.getClaim().setUsername("abc");
t.getClaim().setValidUntil(123);
t.getClaim().setIsSuperUser(false);
ticketSignatureService.signTicket(t);
// WHEN
t.getClaim().setUsername("xyz");
boolean isValid = ticketValidityService.isTicketValid(t);
// THEN
Assert.assertFalse(isValid, "Ticket should NOT be valid.");
}
}
private void startNewContext(long now) {
dataContext = new AnnotationConfigApplicationContext();
dataContext.getEnvironment().setActiveProfiles(Profiles.UNIT_TEST);
dataContext.scan("org.diqube");
dataContext.registerBeanDefinition("a", new RootBeanDefinition(TestTicketRsaKeyFileProvider.class));
dataContext.refresh();
ticketSignatureService = dataContext.getBean(TicketSignatureService.class);
ticketValidityService = dataContext.getBean(TicketValidityService.class);
ticketValidityService.setTimestampProvider(() -> now);
}
public static class TestTicketRsaKeyFileProvider implements TicketRsaKeyFileProvider {
static boolean isFilesWithPrivateKeyAreRequired;
static List<Triple<String, IOExceptionSupplier<InputStream>, String>> files;
static void clean() {
isFilesWithPrivateKeyAreRequired = false;
files = new ArrayList<>();
}
@Override
public CompletableFuture<List<Triple<String, IOExceptionSupplier<InputStream>, String>>> getPemFiles() {
return CompletableFuture.completedFuture(files);
}
@Override
public boolean filesWithPrivateKeyAreRequired() {
return isFilesWithPrivateKeyAreRequired;
}
}
}