/gatekeeper

🔐 A lightweight java library which guards your publicly accessible internal implementations.

Primary LanguageJavaApache License 2.0Apache-2.0

Actions Status Security Rating Coverage Apache2 license Maven Central javadoc

SonarCloud

Gatekeeper 🔐 Tweet

braces-clipart-punctuation-6-original

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:

Install with Maven

<dependency>
    <groupId>io.github.hakky54</groupId>
    <artifactId>gatekeeper</artifactId>
    <version>1.0.3</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:

  1. Calling the protected class with a class that has the same class name and package to specified allowable class.
  2. 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:

  • Give it a star
  • Share it with a Tweet
  • Submit a PR

Resources