sgammon/GUST

View on GitHub
samples/todolist/src/server/TodolistInterceptor.kt

Summary

Maintainability
A
0 mins
Test Coverage
/*
 * Copyright © 2020, The Gust Framework Authors. All rights reserved.
 *
 * The Gust/Elide framework and tools, and all associated source or object computer code, except where otherwise noted,
 * are licensed under the Zero Prosperity license, which is enclosed in this repository, in the file LICENSE.txt. Use of
 * this code in object or source form requires and implies consent and agreement to that license in principle and
 * practice. Source or object code not listing this header, or unless specified otherwise, remain the property of
 * Elide LLC and its suppliers, if any. The intellectual and technical concepts contained herein are proprietary to
 * Elide LLC and its suppliers and may be covered by U.S. and Foreign Patents, or patents in process, and are protected
 * by trade secret and copyright law. Dissemination of this information, or reproduction of this material, in any form,
 * is strictly forbidden except in adherence with assigned license requirements.
 */
package server

import io.grpc.*
import javax.annotation.concurrent.Immutable
import javax.inject.Singleton


/**
 * Intercepts server-side calls to the [TasksService], and performs steps to authenticate the calls before allowing them
 * to proceed. If a given call does not meet the requirements for authentication/authorization, it is rejected with a
 * `403 Forbidden`/`PERMISSION_DENIED` status. If the call is missing authentication credentials entirely, it is
 * rejected with `403 Forbidden`/`AUTHORIZATION_REQUIRED`.
 *
 * Meeting the following requirements constitute valid authentication for use of the Tasks API:
 * - **API key.** The frontend application invoking the service call must affix an API key, which is valid and un-
 *   revoked, and passes any associated validation (for instance, referrer restrictions, for web app keys, and so on).
 *
 * - **Authorization token.** The frontend application invoking the service call must affix an `Authorization` header,
 *   which specifies a `Bearer` token containing a valid, un-expired, and un-revoked Firebase authorization JWT. To
 *   learn more about Firebase Auth, see [here](https://firebase.google.com/docs/auth). To learn more about *JSON Web
 *   Tokens*, head over to [jwt.io](https://jwt.io/).
 */
@Singleton
@Immutable
class TodolistInterceptor: ServerInterceptor {
  /**
   * Performs the interception of RPC traffic through the [TasksService], enforces authentication requirements like API
   * key presence and validity, and loads the active user through any affixed `Authorization` header. If *any* of the
   * described steps fail, the request is rejected. How it is rejected is based on the circumstances, but generally the
   * HTTP status failure code is always `403`.
   *
   * If the interceptor is able to load authentication and authorization credentials are properly validate them, it then
   * prepares the loaded values for downstream use by attaching them to the active gRPC context (see [io.grpc.Context]).
   * Keys for injected context items are exposed statically on this class, so that downstream actors may easily
   * reference them.
   *
   * @param call Server-side call being intercepted in this interceptor invocation.
   * @param metadata Metadata for the call, which roughly equates to the request's HTTP headers.
   * @param handler Tip of the handler chain for this call, which we should pass the call to, in order to continue RPC
   *        processing. This invokes the service method, any associated logic, etc., and hopefully completes the call.
   * @return Listener, which wraps the provided server [call] and [metadata], and eventually dispatches [handler] if
   *         auth details are processed and applied successfully.
   */
  override fun <Request: Any, Response: Any> interceptCall(call: ServerCall<Request, Response>,
                                                           metadata: Metadata,
                                                           handler: ServerCallHandler<Request, Response>):
                                                                                          ServerCall.Listener<Request> {
    return handler.startCall(call, metadata)
  }
}