Class ApiKeyController

java.lang.Object
eu.europeana.apikey.controller.ApiKeyController

@RestController @RequestMapping("/apikey") public class ApiKeyController extends Object
Handles incoming requests for Apikeys that aren't coupled with a Keycloak client Authentication is done using Keycloak authentication, but additional constraints my be checked (for example if the account is a manager account).

Created by luthien on 18/04/2017. Major refactoring by M. Helinski and Patrick Ehlert in September-November 2019 Upgraded to java 11 and spring boot 2 by luthien in December 2019 Another major refactoring to remove automatic link between apikey and client and add support to delete Keycloak client users - by luthien in autumn 2020 (see EA-2156, EA-2234)

  • Constructor Details

    • ApiKeyController

      @Autowired public ApiKeyController(ApiKeyRepo apiKeyRepo, CaptchaManager captchaManager, CustomKeycloakAuthenticationProvider customKeycloakAuthenticationProvider, KeycloakClientManager keycloakClientManager)
      Constructor
      Parameters:
      apiKeyRepo - Repository class instance
      captchaManager - captcha manager class instance
      customKeycloakAuthenticationProvider - Custom keycloak auth provider class instance
      keycloakClientManager - Keycloak client manager class instance
  • Method Details

    • createKey

      @CrossOrigin(maxAge=600L) @PostMapping(produces="application/json") public org.springframework.http.ResponseEntity<Object> createKey(@RequestBody ApiKeyRequest newKeyRequest) throws eu.europeana.api.commons.error.EuropeanaApiException
      Create a new API key with the following mandatory values supplied in a JSON request body: - firstName - lastName - email - appName - company

      The following fields are optional: - website - sector

      The ApiKey field is generated as a unique and random 'readable' lowercase string 8 to 12 characters long, e.g. 'rhossindri', 'viancones' or 'ebobrent' and is checked for uniqueness against the registered ApiKeys values in the Apikey table.

      If creating the Apikey is successful, an email containing the Apikey is sent to the email address supplied in this request.

      Note that this method does not create a Keycloak client.

      Parameters:
      newKeyRequest - requestbody containing supplied values
      Returns:
      JSON response containing the fields annotated with @JsonView(View.Public.class) in ApiKey.java HTTP 201 upon successful ApiKey creation HTTP 400 when a required parameter is missing or invalid OR if an apikey already exist for email,appName HTTP 401 in case of an unauthorised request HTTP 403 if the requested resource is forbidden HTTP 406 if a response MIME type other than application-JSON was requested in the Accept header HTTP 415 if the submitted request does not contain a valid JSON body
      Throws:
      eu.europeana.api.commons.error.EuropeanaApiException - Europeana commons exception abstraction
    • createCaptcha

      @CrossOrigin(maxAge=600L) @PostMapping(path="/captcha", produces="application/json") public org.springframework.http.ResponseEntity<Object> createCaptcha(javax.servlet.http.HttpServletRequest httpServletRequest, @RequestBody ApiKeyRequest newKeyRequest) throws eu.europeana.api.commons.error.EuropeanaApiException
      Create a new API key with the following mandatory values supplied in a JSON request body: - firstName - lastName - email - appName - company

      The following fields are optional: - website - sector

      The ApiKey field is generated as a unique and random 'readable' lowercase string 8 to 12 characters long, e.g. 'rhossindri', 'viancones' or 'ebobrent' and is checked for uniqueness against the registered ApiKeys values in the Apikey table.

      If creating the Apikey is successful, an email containing the Apikey is sent to the email address supplied in this request.

      This method is protected with a captcha token, that must be supplied in the Authorization header. Note that this method does not create a Keycloak client.

      Parameters:
      httpServletRequest - httpServletRequest
      newKeyRequest - requestbody containing supplied values
      Returns:
      JSON response containing the fields annotated with @JsonView(View.Public.class) in ApiKey.java HTTP 201 upon successful ApiKey creation HTTP 400 when a required parameter is missing invalid OR if an apikey already exist for email,appName HTTP 401 in case of an unauthorised request HTTP 403 if the requested resource is forbidden HTTP 406 if a response MIME type other than application-JSON was requested in the Accept header HTTP 415 if the submitted request does not contain a valid JSON body
      Throws:
      eu.europeana.api.commons.error.EuropeanaApiException - when mandatory data are missing; if the combination of email and appname do not already occur in the Apikey table; if the Captcha is missing or its verification failed; when the client who did the request cannot be authenticated
    • createKeyAndClient

      @CrossOrigin(maxAge=600L) @PostMapping(path="/keycloak", produces="application/json", consumes="application/json") public org.springframework.http.ResponseEntity<Object> createKeyAndClient(@RequestBody ApiKeyRequest newKeyRequest) throws eu.europeana.api.commons.error.EuropeanaApiException
      Create a new API key - Keycloak Client pair, with the following mandatory values supplied in a JSON request body: - firstName - lastName - email - appName - company

      The following fields are optional: - website - sector

      The ApiKey field is generated as a unique and random 'readable' lowercase string 8 to 12 characters long, e.g. 'rhossindri', 'viancones' or 'ebobrent' and is checked for uniqueness against the registered ApiKeys values in the Apikey table.

      The Keycloak Client will be linked to this Apikey in the following way (referring to database columns): - the Client's 'client_id' column matches the Apikey's 'apikey' column - the Client's 'id' column matches the Apikey's 'keycloakid' column

      Keycloak generates a Client secret (password) to be used together with the Apikey. If creating the Apikey and Client is successful, an email containing the Apikey and Client secret is sent to the email address supplied in this request.

      HTTP 201 upon successful ApiKey creation HTTP 400 when a required parameter is missing or invalid OR if an apikey already exist for email,appName HTTP 401 in case of an unauthorised request HTTP 403 if the requested resource is forbidden HTTP 406 if a response MIME type other than application-JSON was requested in the Accept header HTTP 415 if the submitted request does not contain a valid JSON body

      Parameters:
      newKeyRequest - requestbody containing supplied values
      Returns:
      JSON response containing the fields annotated with @JsonView(View.Public.class) in ApiKey.java
      Throws:
      eu.europeana.api.commons.error.EuropeanaApiException - if supplied credentials aren't authorised; when mandatory data are missing; if the combination of email and appname do not already occur in the Apikey table; when a problem occurs creating the Client; when there is a problem sending the confirmation email to the associated email address
    • addClient

      @PostMapping(path="/keycloak/{apiKey}") public org.springframework.http.ResponseEntity<org.springframework.http.HttpStatus> addClient(@PathVariable("apiKey") String apiKey) throws eu.europeana.api.commons.error.EuropeanaApiException
      Create a Keycloak client linked to the supplied Apikey. When successful, a Keycloak client linked to the Apikey will be present on the Keycloak server.

      This Keycloak Client will be linked to the supplied Apikey in the following way (referring to database columns): - the Client's 'client_id' column matches the Apikey's 'apikey' column - the Client's 'id' column matches the Apikey's 'keycloakid' column

      Keycloak generates a Client secret (password) to be used together with the Apikey. If creating the Client is successful, an email containing the Client secret is sent to the email address supplied in this request.

      TODO check error responses

      HTTP 201 upon successful Client creation HTTP 400 when a required parameter is missing or invalid OR if an apikey already exist for email,appName HTTP 401 in case of an unauthorised request HTTP 403 if the requested resource is forbidden HTTP 406 if a response MIME type other than application-JSON was requested in the Accept header HTTP 415 if the submitted request does not contain a valid JSON body

      Parameters:
      apiKey - apikey for which the client should be created
      Returns:
      response with created ApiKey details HTTP 201 upon successful ApiKey creation
      Throws:
      eu.europeana.api.commons.error.EuropeanaApiException - if supplied credentials aren't authorised or when the Apikey wasn't found; when there is already a Keycloak Client added to the supplied Apikey; when a problem occurs creating the Client; when there is a problem sending the confirmation email to the associated email address
    • read

      @CrossOrigin(maxAge=600L) @GetMapping(path="/{apikey}", produces="application/json") public ApiKey read(@PathVariable("apikey") String apiKey) throws eu.europeana.api.commons.error.EuropeanaApiException
      Retrieves the details associated with the registration of a given ApiKey

      Return statuses: HTTP 200 upon successful execution HTTP 401 When requested api key does not belong to the authenticated client or this client is not a manager client HTTP 404 when the requested ApiKey is not found in the database HTTP 406 if a response MIME type other than application/JSON was requested in the Accept header

      Parameters:
      apiKey - string identifying the Apikey
      Returns:
      JSON response containing the fields annotated with @JsonView(View.Public.class) in ApiKey.java
      Throws:
      eu.europeana.api.commons.error.EuropeanaApiException - if supplied credentials aren't authorised or when the Apikey wasn't found
    • update

      @CrossOrigin(maxAge=600L) @PutMapping(value="/{apikey}", produces="application/json") public ApiKey update(@PathVariable("apikey") String apiKey, @RequestBody ApiKeyRequest updateKeyRequest) throws eu.europeana.api.commons.error.EuropeanaApiException
      Changes the registration details of an existing API key for the following public and non-generated values when supplied in the JSON request body:

      - firstName - lastName - email - company - appName - sector

      If this method finds a linked Keycloak Client, it also updates that!

      Return statuses: HTTP 200 upon successful ApiKey update HTTP 400 when a required parameter is missing HTTP 401 in case of an unauthorised request (or client credential authentication fails) HTTP 403 if the requested resource is forbidden HTTP 404 if the apikey is not found HTTP 406 if a response MIME type other than application/JSON was requested in the Accept header HTTP 410 if the apikey is invalidated / deprecated HTTP 415 if the submitted request does not contain a valid JSON body

      Parameters:
      apiKey - string identifying the Apikey
      updateKeyRequest - RequestBody containing supplied values
      Returns:
      JSON response containing the fields annotated with @JsonView(View.Public.class) in ApiKey.java
      Throws:
      eu.europeana.api.commons.error.EuropeanaApiException - if supplied credentials aren't authorised; when the Api key is disabled; in the case associated Client exists: when there is a problem updating that Client in Keycloak
    • disable

      @CrossOrigin(maxAge=600L) @PutMapping(path="/{apikey}/disable") public org.springframework.http.ResponseEntity<Object> disable(@PathVariable("apikey") String apiKey) throws eu.europeana.api.commons.error.EuropeanaApiException
      Disables / deprecates a given ApiKey. This is achieved by setting the deprecation date column of the given key to the current time. If this method finds a linked Keycloak Client, it also disables that. No data are deleted by this method.

      Return statuses:

      HTTP 401 in case of an unauthorised request HTTP 403 if the requested resource is forbidden HTTP 404 if the apikey is not found HTTP 410 when the requested ApiKey is already deprecated (i.e. has a past deprecationdate)

      Addionally, the field 'ApiKey-not-found' containing the string "apikey-not-found" will be available in the response header to help telling this HTTP 404 apart from one returned by the webserver for other reasons

      Parameters:
      apiKey - string identifying the Apikey
      Returns:
      HTTP 204 upon successful execution
      Throws:
      eu.europeana.api.commons.error.EuropeanaApiException - if supplied credentials aren't authorised; when the Api key is already disabled; in the case associated Client exists: when there is a problem disabling that Client in Keycloak
    • enable

      @CrossOrigin(maxAge=600L) @PutMapping(path="/{apikey}/enable") public ApiKey enable(@PathVariable("apikey") String apiKey) throws eu.europeana.api.commons.error.EuropeanaApiException
      Re-enables a given invalid ApiKey (of which the deprecationdate column has previously been set to a past time). This is achieved by removing the contents of the deprecationdate column for this ApiKey.

      If this method finds a linked Keycloak Client, it also enables that. No data are deleted by this method.

      Return statuses:

      HTTP 200 upon successful ApiKey update HTTP 400 when a required parameter is missing, has an invalid value or when the Apikey is not deprecated HTTP 401 in case of an unauthorised request HTTP 403 if the requested resource is forbidden HTTP 404 if the apikey is not found

      Parameters:
      apiKey - the Apikey to enable
      Returns:
      JSON response containing the fields annotated with @JsonView(View.Public.class) in ApiKey.java
      Throws:
      eu.europeana.api.commons.error.EuropeanaApiException - if supplied credentials aren't authorised; when the Api key is not deprecated; when an associated Client exists: when there is a problem enabling that Client in Keycloak
    • delete

      @CrossOrigin(maxAge=600L) @DeleteMapping(path="/{apikey}") public org.springframework.http.ResponseEntity<Object> delete(@PathVariable("apikey") String apiKey) throws eu.europeana.api.commons.error.EuropeanaApiException
      This method deletes the apikey identified by the supplied string. NOTE: this actually deletes the apikey row from the database, as opposed to disabling it!

      NOTE: if this method finds a linked Keycloak Client, it also deletes that.

      Return statuses:

      HTTP 401 in case of an unauthorised request HTTP 403 if the requested resource is forbidden HTTP 404 when the requested keycloak identifier is not found in the database

      Parameters:
      apiKey - the Api key string
      Returns:
      HTTP 204 upon successful execution
      Throws:
      eu.europeana.api.commons.error.EuropeanaApiException - if supplied credentials aren't authorised; if Keycloak client cannot be deleted or when a problem occurs communicating with Keycloak
    • validate

      @PostMapping(path="/validate") public org.springframework.http.ResponseEntity<Object> validate(javax.servlet.http.HttpServletRequest httpServletRequest) throws eu.europeana.api.commons.error.EuropeanaApiException
      Validates a given ApiKey. Sets last access date and activation date (if not set, ie. first access) with the current date and +1 increments the usage count of this ApiKey.

      Return statuses:

      HTTP 400 bad request when header does not contain api key HTTP 401 in case of an unauthorised request (here: if the apikey is not registered) HTTP 410 when the requested ApiKey is deprecated (i.e. has a past deprecationdate)

      Parameters:
      httpServletRequest - request
      Returns:
      HTTP 204 upon successful validation
      Throws:
      eu.europeana.api.commons.error.EuropeanaApiException - EuropeanaApiException
    • copyValuesToApiKey

      protected void copyValuesToApiKey(ApiKey apiKey, ApiKeyRequest keyRequest)
      Copy values to api key.
      Parameters:
      apiKey - the api key
      keyRequest - the key request
    • checkManagerCredentials

      protected KeycloakAuthenticationToken checkManagerCredentials() throws ForbiddenException
      Check manager credentials keycloak authentication token.
      Returns:
      the keycloak authentication token
      Throws:
      ForbiddenException - forbidden exception
    • checkManagerOrOwnerCredentials

      protected void checkManagerOrOwnerCredentials(String id) throws ForbiddenException
      Check manager or owner credentials.
      Parameters:
      id - the id
      Throws:
      ForbiddenException - forbidden exception
    • checkMandatoryFieldsAndTrim

      protected ApiKeyRequest checkMandatoryFieldsAndTrim(ApiKeyRequest apiKeyUpdate) throws MissingDataException
      Check mandatory fields and trim api key request.
      Parameters:
      apiKeyUpdate - the api key update
      Returns:
      the api key request
      Throws:
      MissingDataException - missing data exception
    • checkIfKeyExists

      protected ApiKey checkIfKeyExists(String id) throws ApiKeyNotFoundException
      Check if key exists api key.
      Parameters:
      id - Apikey to check
      Returns:
      api key
      Throws:
      ApiKeyNotFoundException - the api key not found exception
    • checkKeyDeprecated

      protected void checkKeyDeprecated(ApiKey key) throws ApiKeyDeprecatedException
      Check key deprecated.
      Parameters:
      key - Apikey to check
      Throws:
      ApiKeyDeprecatedException - description
    • checkKeyEmailAppNameExist

      protected void checkKeyEmailAppNameExist(String email, String appName) throws ApiKeyExistsException
      Check key email app name exist.
      Parameters:
      email - description
      appName - description
      Throws:
      ApiKeyExistsException - description
    • generatePublicKey

      protected String generatePublicKey()
      Generate a new Apikey (public ID). Note that this method is identical to how an Apikey / Keycloak Client ID is generated except that it does not check against Keycloak for uniqueness, but against the Apikey table.
      Returns:
      newly generated public ApiKey