Skip to content

Commit e6f9729

Browse files
authored
Setup publishing to GitHub Packages, bump version to 1.0.0, fix tests (#4) (#3)
* test: get rid of JMockit and use raw reflection to make tests stable (#3) Signed-off-by: Mart Somermaa <[email protected]> * ci: setup publishing to GitHub Packages, bump version to 1.0.0 (#3) Signed-off-by: Mart Somermaa <[email protected]> Co-authored-by: Mart Somermaa <[email protected]>
1 parent d209e0e commit e6f9729

File tree

12 files changed

+144
-88
lines changed

12 files changed

+144
-88
lines changed

.github/workflows/maven-build.yml

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,27 @@
11
name: Maven build
22

3-
on: [push, pull_request]
3+
on: [ push, pull_request ]
44

55
jobs:
66
build:
77
runs-on: ubuntu-latest
88

99
steps:
10-
- uses: actions/checkout@v2
11-
- uses: actions/setup-java@v1
12-
with:
13-
java-version: 1.8
14-
- name: Cache Maven packages
15-
uses: actions/cache@v1
16-
with:
17-
path: ~/.m2
18-
key: ${{ runner.os }}-m2-v8-${{ hashFiles('**/pom.xml') }}
19-
restore-keys: ${{ runner.os }}-m2-v8
20-
- name: Build
21-
run: mvn --batch-mode compile
22-
- name: Test
23-
run: |
24-
mvn -version
25-
mvn --batch-mode verify
10+
- uses: actions/checkout@v2
11+
12+
- uses: actions/setup-java@v1
13+
with:
14+
java-version: 1.8
15+
16+
- name: Cache Maven packages
17+
uses: actions/cache@v1
18+
with:
19+
path: ~/.m2
20+
key: ${{ runner.os }}-m2-v8-${{ hashFiles('**/pom.xml') }}
21+
restore-keys: ${{ runner.os }}-m2-v8
22+
23+
- name: Build
24+
run: mvn --batch-mode compile
25+
26+
- name: Test
27+
run: mvn --batch-mode verify

.github/workflows/maven-deploy.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: Deploy to Github Packages
2+
3+
on:
4+
release:
5+
types: [ created ]
6+
7+
jobs:
8+
build:
9+
runs-on: ubuntu-latest
10+
11+
steps:
12+
- uses: actions/checkout@v2
13+
14+
- uses: actions/setup-java@v1
15+
with:
16+
java-version: 1.8
17+
18+
- name: Cache Maven packages
19+
uses: actions/cache@v1
20+
with:
21+
path: ~/.m2
22+
key: ${{ runner.os }}-m2-v8-${{ hashFiles('**/pom.xml') }}
23+
restore-keys: ${{ runner.os }}-m2-v8
24+
25+
- name: Deploy to GitHub Packages
26+
env:
27+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
28+
run: mvn --batch-mode deploy

.gitlab-ci-mvn-settings.xml

Lines changed: 0 additions & 16 deletions
This file was deleted.

pom.xml

Lines changed: 9 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,20 @@
55
<modelVersion>4.0.0</modelVersion>
66
<artifactId>authtoken-validation</artifactId>
77
<groupId>org.webeid.security</groupId>
8-
<version>1.0.0-SNAPSHOT</version>
8+
<version>1.0.0</version>
99
<packaging>jar</packaging>
1010
<name>authtoken-validation</name>
1111
<description>Web eID authentication token validation library for Java</description>
1212

1313
<properties>
14-
<!-- Build properties -->
1514
<maven.version>3.3.9</maven.version>
16-
<maven-surefire-plugin.version>2.22.1</maven-surefire-plugin.version>
15+
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
1716
<java.version>1.8</java.version>
1817
<jjwt.version>0.11.2</jjwt.version>
1918
<slf4j.version>1.7.30</slf4j.version>
2019
<caffeine.version>2.8.5</caffeine.version>
2120
<junit-jupiter.version>5.6.2</junit-jupiter.version>
2221
<assertj.version>3.17.2</assertj.version>
23-
<jmockit.version>1.44</jmockit.version>
2422
<jacoco.version>0.8.5</jacoco.version>
2523
<sonar.coverage.jacoco.xmlReportPaths>
2624
${project.basedir}/../jacoco-coverage-report/target/site/jacoco-aggregate/jacoco.xml
@@ -92,12 +90,6 @@
9290
<version>${assertj.version}</version>
9391
<scope>test</scope>
9492
</dependency>
95-
<dependency>
96-
<groupId>org.jmockit</groupId>
97-
<artifactId>jmockit</artifactId>
98-
<version>${jmockit.version}</version>
99-
<scope>test</scope>
100-
</dependency>
10193
<dependency>
10294
<groupId>org.slf4j</groupId>
10395
<artifactId>slf4j-simple</artifactId>
@@ -121,13 +113,10 @@
121113
<build>
122114
<plugins>
123115
<plugin>
116+
<!-- Surefire plugin 2.22+ is needed for JUnit 5 -->
117+
<groupId>org.apache.maven.plugins</groupId>
124118
<artifactId>maven-surefire-plugin</artifactId>
125119
<version>${maven-surefire-plugin.version}</version>
126-
<configuration>
127-
<argLine>
128-
@{argLine} -javaagent:${settings.localRepository}/org/jmockit/jmockit/${jmockit.version}/jmockit-${jmockit.version}.jar
129-
</argLine>
130-
</configuration>
131120
</plugin>
132121
<plugin>
133122
<!-- Generate a coverage XML file for Sonar -->
@@ -152,21 +141,15 @@
152141
</plugins>
153142
</build>
154143

155-
<!-- For publishing the library in GitLab Maven repository, remove later -->
156-
<repositories>
157-
<repository>
158-
<id>gitlab-maven</id>
159-
<url>https://gitlab.com/api/v4/projects/${env.CI_PROJECT_ID}/packages/maven</url>
160-
</repository>
161-
</repositories>
144+
<!-- For publishing the library to GitHub Packages -->
162145
<distributionManagement>
163146
<repository>
164-
<id>gitlab-maven</id>
165-
<url>https://gitlab.com/api/v4/projects/${env.CI_PROJECT_ID}/packages/maven</url>
147+
<id>github</id>
148+
<url>https://maven.pkg.github.com/web-eid/web-eid-authtoken-validation-java</url>
166149
</repository>
167150
<snapshotRepository>
168-
<id>gitlab-maven</id>
169-
<url>https://gitlab.com/api/v4/projects/${env.CI_PROJECT_ID}/packages/maven</url>
151+
<id>github</id>
152+
<url>https://maven.pkg.github.com/web-eid/web-eid-authtoken-validation-java</url>
170153
</snapshotRepository>
171154
</distributionManagement>
172155

src/main/java/org/webeid/security/validator/validators/FunctionalSubjectCertificateValidators.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
package org.webeid.security.validator.validators;
2424

25+
import io.jsonwebtoken.Clock;
2526
import org.slf4j.Logger;
2627
import org.slf4j.LoggerFactory;
2728
import org.webeid.security.exceptions.*;
@@ -30,6 +31,7 @@
3031
import java.security.cert.CertificateExpiredException;
3132
import java.security.cert.CertificateNotYetValidException;
3233
import java.security.cert.CertificateParsingException;
34+
import java.util.Date;
3335
import java.util.List;
3436

3537
public final class FunctionalSubjectCertificateValidators {
@@ -45,7 +47,8 @@ public final class FunctionalSubjectCertificateValidators {
4547
*/
4648
public static void validateCertificateExpiry(AuthTokenValidatorData actualTokenData) throws TokenValidationException {
4749
try {
48-
actualTokenData.getSubjectCertificate().checkValidity();
50+
// Use JJWT Clock interface so that the date can be mocked in tests.
51+
actualTokenData.getSubjectCertificate().checkValidity(DefaultClock.INSTANCE.now());
4952
LOG.debug("User certificate is valid.");
5053
} catch (CertificateNotYetValidException e) {
5154
throw new UserCertificateNotYetValidException(e);
@@ -78,4 +81,14 @@ public static void validateCertificatePurpose(AuthTokenValidatorData actualToken
7881
private FunctionalSubjectCertificateValidators() {
7982
throw new IllegalStateException("Functional class");
8083
}
84+
85+
public static class DefaultClock implements Clock {
86+
87+
public static final Clock INSTANCE = new DefaultClock();
88+
89+
public Date now() {
90+
return new Date();
91+
}
92+
93+
}
8194
}

src/test/java/org/webeid/security/testutil/AbstractTestWithMockedDate.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626

2727
import java.text.ParseException;
2828

29+
import static org.webeid.security.testutil.Dates.setMockedDefaultJwtParserDate;
30+
2931
public abstract class AbstractTestWithMockedDate extends AbstractTestWithCache {
3032

3133
@Override
@@ -34,8 +36,8 @@ protected void setup() {
3436
super.setup();
3537
try {
3638
// Authentication token is valid until 2020-04-14
37-
Dates.setMockedDate(Dates.create("2020-04-11"));
38-
} catch (ParseException e) {
39+
setMockedDefaultJwtParserDate(Dates.create("2020-04-11"));
40+
} catch (ParseException | NoSuchFieldException | IllegalAccessException e) {
3941
throw new RuntimeException(e);
4042
}
4143
}

src/test/java/org/webeid/security/testutil/Dates.java

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,12 @@
2323
package org.webeid.security.testutil;
2424

2525
import com.fasterxml.jackson.databind.util.StdDateFormat;
26-
import mockit.Mock;
27-
import mockit.MockUp;
26+
import io.jsonwebtoken.Clock;
27+
import io.jsonwebtoken.impl.DefaultClock;
28+
import org.webeid.security.validator.validators.FunctionalSubjectCertificateValidators;
2829

30+
import java.lang.reflect.Field;
31+
import java.lang.reflect.Modifier;
2932
import java.text.ParseException;
3033
import java.util.Date;
3134

@@ -36,13 +39,31 @@ public static Date create(String iso8601Date) throws ParseException {
3639
return STD_DATE_FORMAT.parse(iso8601Date);
3740
}
3841

39-
public static void setMockedDate(Date mockedDate) {
40-
new MockUp<System>() {
41-
@Mock
42-
public long currentTimeMillis() {
43-
return mockedDate.getTime();
44-
}
45-
};
42+
public static void setMockedDefaultJwtParserDate(Date mockedDate) throws NoSuchFieldException, IllegalAccessException {
43+
setClockField(DefaultClock.class, mockedDate);
44+
}
45+
46+
public static void setMockedFunctionalSubjectCertificateValidatorsDate(Date mockedDate) throws NoSuchFieldException, IllegalAccessException {
47+
setClockField(FunctionalSubjectCertificateValidators.DefaultClock.class, mockedDate);
48+
}
49+
50+
public static void resetMockedFunctionalSubjectCertificateValidatorsDate() throws NoSuchFieldException, IllegalAccessException {
51+
setClockField(FunctionalSubjectCertificateValidators.DefaultClock.class, new Date());
52+
}
53+
54+
private static void setClockField(Class<? extends Clock> cls, Date date) throws NoSuchFieldException, IllegalAccessException {
55+
final Field clockField = cls.getDeclaredField("INSTANCE");
56+
setFinalStaticField(clockField, (Clock) () -> date);
57+
}
58+
59+
private static void setFinalStaticField(Field field, Object newValue) throws NoSuchFieldException, IllegalAccessException {
60+
field.setAccessible(true);
61+
62+
final Field modifiersField = Field.class.getDeclaredField("modifiers");
63+
modifiersField.setAccessible(true);
64+
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
65+
66+
field.set(null, newValue);
4667
}
4768

4869
}

src/test/java/org/webeid/security/validator/ClockSkewTest.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,21 +30,22 @@
3030

3131
import static org.assertj.core.api.Assertions.assertThatCode;
3232
import static org.assertj.core.api.Assertions.assertThatThrownBy;
33+
import static org.webeid.security.testutil.Dates.setMockedDefaultJwtParserDate;
3334

3435
class ClockSkewTest extends AbstractTestWithValidatorAndCorrectNonce {
3536

3637
@Test
3738
void blockLargeClockSkew4min() throws Exception {
3839
// Authentication token expires at 2020-04-14 13:32:49
39-
Dates.setMockedDate(Dates.create("2020-04-14T13:36:49Z"));
40+
setMockedDefaultJwtParserDate(Dates.create("2020-04-14T13:36:49Z"));
4041
assertThatThrownBy(() -> validator.validate(Tokens.SIGNED))
4142
.isInstanceOf(TokenExpiredException.class);
4243
}
4344

4445
@Test
4546
void allowSmallClockSkew2min() throws Exception {
4647
// Authentication token expires at 2020-04-14 13:32:49
47-
Dates.setMockedDate(Dates.create("2020-04-14T13:30:49Z"));
48+
setMockedDefaultJwtParserDate(Dates.create("2020-04-14T13:30:49Z"));
4849
assertThatCode(() -> validator.validate(Tokens.SIGNED))
4950
.doesNotThrowAnyException();
5051
}

src/test/java/org/webeid/security/validator/NonceTest.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.webeid.security.testutil.Tokens;
3232

3333
import static org.assertj.core.api.Assertions.assertThatThrownBy;
34+
import static org.webeid.security.testutil.Dates.setMockedDefaultJwtParserDate;
3435

3536
class NonceTest extends AbstractTestWithValidator {
3637

@@ -50,30 +51,30 @@ void validateExpiredNonce() {
5051

5152
@Test
5253
void testNonceMissing() throws Exception {
53-
Dates.setMockedDate(Dates.create("2020-04-14T13:00:00Z"));
54+
setMockedDefaultJwtParserDate(Dates.create("2020-04-14T13:00:00Z"));
5455
assertThatThrownBy(() -> validator.validate(Tokens.NONCE_MISSING))
5556
.isInstanceOf(TokenParseException.class)
5657
.hasMessageStartingWith("nonce field must be present and not empty in authentication token body");
5758
}
5859

5960
@Test
6061
void testNonceEmpty() throws Exception {
61-
Dates.setMockedDate(Dates.create("2020-04-14T13:00:00Z"));
62+
setMockedDefaultJwtParserDate(Dates.create("2020-04-14T13:00:00Z"));
6263
assertThatThrownBy(() -> validator.validate(Tokens.NONCE_EMPTY))
6364
.isInstanceOf(TokenParseException.class)
6465
.hasMessageStartingWith("nonce field must be present and not empty in authentication token body");
6566
}
6667

6768
@Test
6869
void testTokenNonceNotString() throws Exception {
69-
Dates.setMockedDate(Dates.create("2020-04-14T13:00:00Z"));
70+
setMockedDefaultJwtParserDate(Dates.create("2020-04-14T13:00:00Z"));
7071
assertThatThrownBy(() -> validator.validate(Tokens.NONCE_NOT_STRING))
7172
.isInstanceOf(TokenParseException.class);
7273
}
7374

7475
@Test
7576
void testNonceTooShort() throws Exception {
76-
Dates.setMockedDate(Dates.create("2020-04-14T13:00:00Z"));
77+
setMockedDefaultJwtParserDate(Dates.create("2020-04-14T13:00:00Z"));
7778
putTooShortNonceToCache();
7879
assertThatThrownBy(() -> validator.validate(Tokens.NONCE_TOO_SHORT))
7980
.isInstanceOf(TokenParseException.class);

src/test/java/org/webeid/security/validator/OcspTest.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,15 @@
2424

2525
import org.junit.jupiter.api.BeforeEach;
2626
import org.junit.jupiter.api.Test;
27+
import org.webeid.security.exceptions.TokenValidationException;
2728
import org.webeid.security.exceptions.UserCertificateRevocationCheckFailedException;
2829
import org.webeid.security.exceptions.UserCertificateRevokedException;
2930
import org.webeid.security.testutil.AbstractTestWithMockedDateAndCorrectNonce;
3031
import org.webeid.security.testutil.Tokens;
3132

3233
import java.security.cert.CertificateException;
3334

35+
import static org.assertj.core.api.Assertions.assertThat;
3436
import static org.assertj.core.api.Assertions.assertThatThrownBy;
3537
import static org.webeid.security.testutil.AuthTokenValidators.getAuthTokenValidatorWithOcspCheck;
3638

@@ -51,14 +53,16 @@ protected void setup() {
5153

5254
@Test
5355
void detectRevokedUserCertificate() {
54-
// This test used to have flaky results, due to occasionally failing
55-
// OCSP requests. Therefore, the failed revocation check is now handled
56-
// as passing.
57-
assertThatThrownBy(() -> validator.validate(Tokens.SIGNED))
58-
.isInstanceOfAny(
56+
// This test had flaky results as OCSP requests sometimes failed, sometimes passed.
57+
// Hence the catch which may or may not execute instead of assertThatThrownBy().
58+
try {
59+
validator.validate(Tokens.SIGNED);
60+
} catch (TokenValidationException e) {
61+
assertThat(e).isInstanceOfAny(
5962
UserCertificateRevokedException.class,
6063
UserCertificateRevocationCheckFailedException.class
6164
);
65+
}
6266
}
6367

6468
}

0 commit comments

Comments
 (0)