Monthly Archives: December 2020

How to add conditions to Java Bean validation?

Published / by msaladin / Leave a Comment

Today I faced a very common problem and I did not find out how to solve it for some time. I am using Java Beans Validation (JSR 380), so this means that I can use annotations in my class and at the time of validation, my framework (in this case Springboot) is automatically trying to validate the values of the class.
Example:

public class ClassToValidate {
  @NotNull
  private String email;
}

This works fine, and I can add annotations like:

  • @NotNull
  • @Size(min = 2, max = 64)
  • etc…

But my problem was that I wanted to have a special kind of validation:

  • If the field is null, this is ok for me.
  • But if the field is not null, then I want to add special validation (like checking that the minimal and maximal length of the string is validated and is between 2 and 64 chars).

The Java Beans validation provides a very helpful way how to create custom annotations, and this is what is needed to have such a conditional (OR) validation logic. Just create your own annotations, and combine them using OR:

public class ClassToValidate {
    @ConstraintComposition(CompositionType.OR)
    @Null
    @Size(min =2, max=256)
    @Target({ElementType.METHOD, ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    @Constraint(validatedBy = {})
    public @interface EmailOrNull {
        String message() default "Not valid";

        Class[] groups() default {};

        Class[] payload() default {};
    }

    @EmailOrNull
    private String email;
}

I found some interesting information here:
JBOSS Hibernate validator documentation

Searching git repo for source-code change

Published / by msaladin / Leave a Comment

Today I wanted to search for a Java class in my git repository that no longer exists. I can recall that I had used some code snippets in a class that no longer exists, but I cannot recall the class name, and I cannot recall which commit message I used to remove the class from the repository. My question was: Can I full-search my git repo?

Answer: Yes. It is possible to search the whole git for a regular expression. Let’s say I knew that in the class I was searching, I had the following code snippet “Jwts.builder()”, so I can search the whole repository for this snippet:

git grep "Jwts.builder()" $(git rev-list --all)

The result I get is a list of all files where the search string exists, and the git commit hash. With this you can checkout the revision (git commit hash), search for the file, and then continue to navigate from there on using your favorite IDE.

Links:

Renew JWT token in Angular

Published / by msaladin / Leave a Comment

Currently I am working on a small project with a frontend application in Angular (version 10) and a backend in Springboot. Because this application is rather small I decided to issue the JWT token in the backend and not use an external Authorization provider like Azure. So the workflow goes like this:

  • User enters credentials
  • Frontend calls backend /login, backend verifies hashed password and if successful returns a self-signed JWT token
  • Frontend stores the JWT token in session-storage, and sends the token in the http header for each subsequent request
  • In this blog post I discuss how the frontend app assures that there is always a valid token sent along with each http request to the backend.

    Step 1: Include token in http header

    In Angular you can define a http interceptor which checks the session-storage for the token, and includes it in the http header. Let’s reuse an existing header for this which is the Authorization header. See RFC 6750 for more details. The interceptor code looks quite simple:

    @Injectable()
    export class AuthInterceptor implements HttpInterceptor {
    
        intercept(request: HttpRequest, next: HttpHandler): Observable> {
            const idToken = this.localSessionService.getIdToken();
            if (idToken) {
                const cloned = request.clone({
                    headers: request.headers.set('Authorization', 'Bearer ' + idToken)
                });
                return next.handle(cloned);
            } else {
    
                return next.handle(request);
            }
        }
    }
    

    The interceptor needs to be defined in the Angular module as a provider, so my app.module.ts file includes this:

    ...
    providers: [
      {provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true},
      {provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true}
    ],
    

    Step 2: Renew token

    But a token is not really valid forever, e.g. in my application the token will be valid for 60 minutes. After that, the token is no longer valid, and when the frontend application would not check for this use-case, after 60 minutes, the token expires, the backend returns a 403 http error code, and the frontend application displays the login-screen again… This is not really user-friendly.

    What I want to achieve is that the token is renewed automatically, say, when the token is only 30 minutes valid. There are a lot of OAUTH2 libraries which do the token-renewal deeply hidden in an own iframe (e.g. MSAL Angular library) and don’t need any special implementation in the frontend application.

    But in my frontend app I don’t like this kind of magic, so I included it like this:

  • Whenever there is a call to the backend, check whether the time to live (TTL) of the token is smaller than 30 minutes.
  • If yes, then (in the background) invoke a call to /renewToken endpoint and renew the token.
  • Nevertheless, as the token is still valid 30 minutes, the ongoing http call can proceed.
  • It could be that there are lot of http requests going on, and we don’t want to request a token-renewal several times (when the token-renewal request takes too much time), so we need to make sure to note whether we have sent a token-renewal-request, and only send new renewal-requests when there was no request sent earlier. The whole logic takes place in the same interceptor as before:

    @Injectable()
    export class AuthInterceptor implements HttpInterceptor {
    
        private renewTokenRequestSent: boolean;
    
        constructor(private localSessionService: LocalSessionService,
                    private readonly httpHandler: HttpBackend) {
        }
    
        intercept(request: HttpRequest, next: HttpHandler): Observable> {
            const idToken = this.localSessionService.getIdToken();
            if (idToken) {
    
                // *********************************** Changes for token renewal *******************
                const expiresAt = this.localSessionService.getIdTokenExpiresAtAsUnitTimestamp();
                const loggedInTTL = moment.duration(moment(expiresAt).diff(moment())).asSeconds();
                if (!this.renewTokenRequestSent) {
                    // Check age of token and if necessary, renew it
                    if (loggedInTTL < (30*60) ) {
                        this.invokeRenewTokenAysnc(idToken);
                    }
                }
                // *******************************************************************************
                const cloned = request.clone({
                    headers: request.headers.set('Authorization', 'Bearer ' + idToken)
                });
                return next.handle(cloned);
            } else {
    
                return next.handle(request);
            }
        }
    }
    

    First, we calculate the TTL of the current token using moment.js. To make this calculation faster I store the Unix timestamp (number) in the localSessionService (moment.valueOf()). If the TTL is smaller than our threshold (30 minutes) the method invokeRenewTokenAysnc is invoked. After that, the ordinary http request continues (next.handle(cloned).

    The method invokeRenewTokenAysnc is quite straight-forward:

  • Don't use an ordinary httpClient as this would mean that there are http interceptors, and we don't want to have http interceptors for the renewal call (this could lead to an infinite loop where the interceptor calls itself infinite times)
  • Make sure that in case of an error the flag (this.renewTokenRequestSent) is reset so that another renewal request will be sent in the future (where maybe the backend server is up and running again)
  • I thought long about error-handling, but actually the error handling callback does not need to do much except log the exception. There is an ongoing http request, and this ongoing http request has a valid error handling. The token-renewal request is invoked in the background, and when the token-renewal fails, our application can do nothing except to try again and again until it works, or until the TTL of the existing token times out.

        private invokeRenewTokenAysnc(idToken: string) {
            // Create own httpClient so that there are no interceptors (e.g. this interceptor) in it, plain vanilla http connection
            const httpClientForRenewal = new HttpClient(this.httpHandler);
            const renewHeaderMap = {
                Authorization: 'Bearer ' + idToken
            };
            const options = {
                headers: new HttpHeaders(renewHeaderMap),
            };
    
            this.renewTokenRequestSent = true;
            httpClientForRenewal.get('/todo/secured/v1/renew', options)
                .pipe(take(1))
                .subscribe(
                    loginResp => this.callbackSuccessRenewToken(loginResp),
                    err => this.callbackErrorRenewToken(err),
                    () => this.callbackCompleteRenewToken()
                );
        }
    
        callbackSuccessRenewToken(authResult: LoginResponse) {
            this.localSessionService.loginSuccessful(authResult);
        }
    
        callbackErrorRenewToken(err: any): void {
            console.error('Error while renewing token. Ignore error and continue (and try again to renew token).');
            // if (err.error instanceof ErrorEvent) {
            //     // *************************************************************************************
            //     // Something could go wrong on the client-side such as a network error that prevents the
            //     // request from completing successfully or an exception thrown in an RxJS operator.
            //     // These errors produce JavaScript ErrorEvent objects.
            //     // *************************************************************************************
            // } else {
            //     // *************************************************************************************
            //     // The backend returned an unsuccessful response code.
            //     // The response body may contain clues as to what went wrong.
            //     // *************************************************************************************
            //     if (err.error.code) {
            //         // Cool, we have a error which we can interpret because it contains the field "code"
            //     } else {
            //         // *************************************************************************************
            //         // We received unknown body, but status is still ok. Mostly this happens when a Proxy/
            //         // LoadBalancer in-between returns a HTML error page.
            //         // *************************************************************************************
            //     }
            // }
            this.callbackCompleteRenewToken();
        }
    
        /**
         * Complete the renewal call, make sure to invoke this method in case of error as well
         */
        callbackCompleteRenewToken(): void {
            this.renewTokenRequestSent = false;
        }
    

    Hope that helps others!