Gatekeeper 🔐
Introduction
Gatekeeper is a library which guards your publicly accessible internal implementations.
History
Library maintainers have a hard time to keep internal implementations internal and prevent it to be accessible by library users. The library maintainer cannot easily change internal implementations as it may lead into breaking changes for the library users. A straight forward method for library maintainers would be making classes package protected and accessible through public api's so-called Service classes. Encapsulation internal api's and exposing it through service classes is the preferred way but cannot be achieved in some use cases. Restrictions by Java Modules will not work if the end-user is not using java modules. Gatekeeper will ensure that these internal implementations remain internal by validating the caller. You as a library developer can choose who is allowed to call your classes.
Minimum requirements:
- Java 8
Install library with:
Maven
Install with<dependency>
<groupId>io.github.hakky54</groupId>
<artifactId>gatekeeper</artifactId>
<version>1.0.2</version>
</dependency>
Install with Gradle
implementation 'io.github.hakky54:gatekeeper:1.0.2'
Install with Scala SBT
libraryDependencies += "io.github.hakky54" % "gatekeeper" % "1.0.2"
Install with Apache Ivy
<dependency org="io.github.hakky54" name="gatekeeper" rev="1.0.2" />
Usage
Internal API - Protected by Gatekeeper
import nl.altindag.gatekeeper.Gatekeeper;
public class FooInternal {
public String hello() {
Gatekeeper.ensureCallerIsAnyOf(FooService.class);
return "Hello";
}
}
Public API - Exposed
public class FooService {
private final FooInternal fooInternal = new FooInternal();
public String hello() {
return fooInternal.hello();
}
}
public class App {
public static void main(String[] args) {
FooService fooService = new FooService();
String hello = fooService.hello();
System.out.println(hello); // ---> prints Hello
FooInternal fooInternal = new FooInternal();
fooInternal.hello(); // ---> throws a (runtime) GatekeeperException with an explaining message
}
}
Bulletproof?
This library provides a protection by checking the caller at runtime, but it is sadly not 100% bulletproof. It just makes it a bit tougher for the end-user to use the protected classes. Unfortunately this protection can be bypassed with two methods:
- Calling the protected class with a class that has the same class name and package to specified allowable class.
- Overriding the jar with a modified version which doesn't validate at all.
You should know about these use cases before considering using this library. It cannot give 100% protection if the end-user is using one of the two methods to bypass it. If you are ok with that, go ahead or else I would recommend to use java's Sealed classes which are available from Java 15 onwards.
Contributing
There are plenty of ways to contribute to this project: