Spring Boot Swagger Keycloak

Spring Boot + Swagger sind ein eingespieltes Team, um die eigenen Rest-APIs als OpenApi Beschreibung zur Verfügung zu stellen. Dafür bedarf es kaum Aufwand, reicht es doch die entsprechenden Abhängigkeiten per Maven zu definieren (für OpenApi 3.0 : org.springdoc, springdoc-openapi-ui).

Klar. In aller Regel wollen wir zusätzliche Information für unsere Schnittstellen bereitstellen und spätestens, wenn unsere Rest-Aufrufe eine Authentifizierung benötigen bedarf es zusätzlicher Konfiguration um z.B. die swagger-ui nutzen zu können. Setzen wir dabei auf eine OAuth2 Variante, z.B. mit Keycloak könnte die einfachste der Konfigurationen so aussehen:

@Configuration
public class OpenApiConfig {

        @Value("${app.version}")
        private String appVersion;

        @Value("${app.name}")
        private String appName;

        @Value("${app.security.auth-server-url}")
        private String authServerUrl;

        @Value("${app.security.realm}")
        private String realm;

        @Value("${app.security.client-ui}")
        private String client;

        @Bean
        public OpenAPI customOpenAPI() {
                OAuthFlows flows = new OAuthFlows();
                OAuthFlow flow = new OAuthFlow();

                flow.setAuthorizationUrl(authServerUrl + "/realms/" + realm + "/protocol/openid-connect/auth");

                Scopes scopes = new Scopes();
                flow.setScopes(scopes);
                flows = flows.implicit(flow);

                return new OpenAPI()
                                .components(new Components().addSecuritySchemes("keycloak",
                                                new SecurityScheme().type(SecurityScheme.Type.OAUTH2).flows(flows)))
                                .info(new Info().title(appName)
                                                .version(appVersion))
                                .addSecurityItem(new SecurityRequirement().addList("keycloak",
                                                Arrays.asList("read", "write")));
        }

}

Angular-CLI Proxy + JEE

In vielen kleinen bis mittleren Projekten wird unsere spätere Angular-Anwendung zusammen mit dem JEE Backend auf ein und demselben Server laufen. Das vereinfacht nicht nur den Betrieb sondern wir müssen uns auch über CORS-Richtlinien keine Gedanken machen.

Doch zumindest während der Entwicklungszeit wollen wir in aller Regel mit unterschiedlichen Servern arbeiten, bietet uns die Angular-CLI mit seinem eigenen kleinen Dev-Server die perfekte Lösung um unsere Anwendung während der Entwicklung zu begutachten. Damit stolpern wir aber über das bereits erwähnte CORS-Thema. Anstatt nun das Test- und oder Entwicklungs-Backend zurecht zu konfigurieren bietet Angular selbst eine einfache und transparente Lösung. Der Angular-Dev-Server lässt sich ganz einfach mittels einer Proxy-Konfiguration ergänzen, sodass alle Anfragen an eine bestimmten URL um geroutet werden. Damit sparen wir uns zum einen unterschiedliche Environment-Konfigurationen (da unsere APIs nun für die Angular Anwendung immer unter z.B. /api/… erreichbar sindund nicht um den Backend-Server ergänzt werden muss (http://localhost:8080/api/..)) und vor allem umgehen wir mit dieser Umleitung die Security-CORS-Regeln die der Browser anwenden würde.

{
  "/api/*": {
    "target": "http://localhost:8080/api",
    "secure": false,
    "logLevel": "debug",
    "changeOrigin": true,
    "pathRewrite": {
      "^/api": ""
    }
  }
}

proxy.conf.json

Diese Konfiguration lässt sich nun ganz einfach per Kommandozeile beim Starten des Dev-Servers ergänzen

"ng serve --proxy-config proxy.conf.json"
** Angular Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ **
: Compiled successfully.
[HPM] Rewriting path from "/api/user" to "/user"
[HPM] GET /api/user ~> http://localhost:8080/api

Angular Theming, Library-Komponenten

In folgendem Artikel: Angular Material Theming haben wir uns bereits angesehen wie wir eigene Themes für Angular Material schreiben. Auch haben wir gesehen wie wir die so definierten Farb-Paletten und Typografie-Elemente in unseren eigenen Komponenten einsetzen können. Das war ganz einfach, durch eine kluge Trennung der Style-Definitionen und einen Import des aktuell verwendeten Themes. Doch was wenn unsere Komponenten nicht Teil unseres Projektes sind, sondern in einem separaten Projekt / eigenen Komponente-Bibliothek ausgelagert sind? Hier haben wir ja keinen direkten Zugriff auf das aktuelle Theme, schließlich wird das ja erst durch die konkrete Anwendung festgelegt.

Unsere eigene Komponenten Bibliothek muss also analog zum Vorgehen bei Angular Materials durch entsprechende Mixin-Funktionen mit dem aktuellen Theme versorgt werden. Um das zu tun bedarf es einiger Vorarbeit innerhalb unserer Komponenten.

Zusätzlich zu der üblichen Komponenten-Style-Datei implementieren wir eine theme.scss für unsere Bibliothek. Diese Datei enthält alle Regeln mit Theme-spezifischen Eigenschaften für die in der Bibliothek enthaltenden Komponenten. Um diese später in den konkreten Anwendungen zu definieren benötigen wir entsprechende Mixin-Funktionen:

@import '~@angular/material/theming';

@mixin ng-lib-theme($theme) {
  $primary: map-get($theme, primary);
  $accent: map-get($theme, accent);

  lib-panel div.body {
    border-top-color: mat-color($primary, 400);
    border-bottom-color: mat-color($accent, 400);
  }
}

@mixin ng-lib-typography($config) {
  lib-panel div.body {
    font-size: mat-font-size($config, title);
  }
}

Wie zu sehen definieren wir jeweils eine eigene Mixin-Funktion für das Theme und Typografie die mit einem entsprechenden Parameter versorgt werden (Theme-Objekt bzw. Typografie-Konfig). Aus dem Theme können wir dann z.B. mittels „map-get“ die einzelnen Paletten extrahieren (primary, accent, warning) die dann wiederum dazu genutzt werden können um konkrete Farbwerte zu ermitteln. Diese werden dann wie bereits gesehen in einzelnen CSS-Regeln verwendet um Theme spezifische Ergänzungen zu den Komponente-Styles zu liefern.

Innerhalb er konkreten Anwendung ähnelt die Registrierung dann erschreckend der von Angular Materials:

@include ng-lib-theme($theme02);
@include ng-lib-typography($custom-typography);

Zugegeben mit „ein bisschen“ CSS ist es hier nicht getan. Auch um die Verwendung von SASS als CSS-Präprozessor kommen wir an dieser Stelle nicht mehr herum. Der ist aber ohnehin zu empfehlen, auch wenn man im eigenen Projekt die Möglichkeiten von SASS vielleicht gar nicht ausschöpft oder sogar nur Kernfunktionen wie die Definition von Variablen nutzt. Ob die Anbindung der eigenen Komponenten an das Material Theming, wie zu letzt gesehen, notwenig ist hängt sicher von der Anwendung selbst ab. Insbesondere bei internen Komponenten-Bibliotheken die keinerlei dynamischen Theming-Funktionalitäten benötigen erfüllt eine zentrale Library mit festgelegtem Look&Feel ( in unserem Beispiel wäre das die theme.scss und variables.scss) sicherlich auch seinen Zweck.

GitHub? Klaro.

maven vulnerability check

Maven ist eine tolle Erfindung. Abhängigkeiten und Versionen deklarieren und den Rest erledigt der Mechanismus ganz im Hintergrund. Im Laufe des Projekt-Lebens lassen sich neue Abhängigkeiten ganz einfach per zusätzlichem XML Eintrag hinzufügen; logisch das man dabei in aller Regel die neueste Version der Bibliothek nimmt die in der verwendeten Architektur möglich ist. Aber Moment… die bestehenden Abhängigkeiten, die teilweise schon Jahre alt sind, sollte man die vielleicht nicht auch mal anheben? Selbst wenn wir keine Features vermissen, kritische Fehler wollen wir doch in unseren Abhängigkeiten und damit in unserer Anwendung nicht dulden…

Eine regelmäßige Kontrolle der Versionen unserer Bibliotheken macht natürlich aus Sicherheitsaspekten Sinn. Dafür sollten wir uns natürlich etwas Hilfe holen, ein Beispiel dafür

OWASP Dependency Check

Eine Organisation die sich um die Analyse und vor allem Protokollierung von Sicherheitslücken in Software kümmert. Passend dazu werden Plugins für Ant, Maven und Jenkins geboten. Die Integration zum Beispiel in Maven ist relativ einfach:

<plugin>
    <groupId>org.owasp</groupId>
    <artifactId>dependency-check-maven</artifactId>
    <version>5.2.4</version>
    <executions>
        <execution>
            <goals>
                <goal>check</goal>
            </goals>
        </execution>
    </executions>
</plugin>   

natürlich lässt sich hier noch eine ganze Menge mehr einstellen ( Doku ). Mit einem entsprechenden Maven-Aufruf

mvn org.owasp:dependency-check-maven:check

Generiert unser Plugin nun ein ansehnliches HTML-Protokoll, auf dessen Basis wir prüfen und entscheiden können, ob die Portierung unserer Bibliotheken notwendig ist:

Das passende Jenkins-Plugin lässt sich darüber hinaus auch mit entsprechenden Schwellwerten versehen um z.B. im NightlyBuild Fehler / Warnung auszugeben und den viel beschäftigten Entwickler auf Handlungsbedarf aufmerksam zu machen 😉