Security

The CoreWallet provides an integral but flexible security mechanism, based on Spring Security.

Role-based access control

Every ExportedService (which is required for exposing services via HttpInvoker in the internal-webapp) requires an authenticated security-context by default, using the @PreAuthorize(SecurityUtils.AUTHENTICATED) annotation, which by default rejects anonymous invocations.

A service-interface or a service-method in an interface can override the default security configuration using the @PreAuthorize(SecurityUtils.*) annotation, e.g. to require specific roles or allow anonymous access as well.

The available roles for these annotations in the CoreWallet are the following:

  • SYSTEM for system security context, typically in batch-jobs
  • ADMIN for internal security context, typically for Admin API calls
  • CONSUMER for Consumer security context (default for every user)
  • MERCHANT for Merchant security context
  • SHOP_CONFIGURATION for ShopConfiguration context (default for ShopConfiguration-authentications)

The security-annotations can be done on every interface where it should apply.

Spring Security will ensure those method will only be called when an appropriate security-context is present, or throw an AccessDeniedException otherwise.

Extension point for role-based access control

The CoreWallet annotations only support high-level roles, but typically for ADMIN there may be a need for a finer role model, as different levels of ADMIN may exist.

This is a product-specific implementation that uses the extension-point MethodAccessRoleProvider which is used to retrieve the required roles for a given method. If any of the returned roles match, access is granted. If no roles match, access is denied (note: this applies when an empty-list is returned by this extension). If null is returned by this extension point, the MethodAccessDecisionVoter abstains from voting, which is the default behavior.

It allows a product to define additional required roles for certain packages, interfaces or methods, and/or different contexts based on the provided ApiRequestInfo object.

Running sub-processes using the system security-context

At times it may be required to execute a certain sub-process that would normally not be possible with the current security-context, e.g. to fetch certain data or trigger a system process.

This can be achieved using the BaseServiceImpl.runWithSystemSecurityContext() methods, which temporarily upgrade the security-context to a SYSTEM security context, and execute the provided callback-method. The method ensures that the security context is downgraded to the original after the callback.

The usage and scope should always be as small as needed, to prevent unnecessary risks of using the SYSTEM security context.

Authorization

Role-based security alone is not enough for proper security, as we must ensure that a user can only access data allowed by the security context. For example, a user should be able to load his own wallet, but not the wallet of another user.

The CoreWallet uses the WalletBaseServiceImpl.checkAuthentication() methods for this. It determines the relevant top-most-entity in the entity-hierarchy (typically a Wallet), and ensures that the current security-context is allowed to access this entity using the AuthenticationService.checkAuthenticationByOwner() method.

The default implementation works as follows:

  1. SYSTEM security-context is always allowed
  2. Anonymous security-context is always denied
  3. ExternalAPI security-context is allowed when the owner of the entity matches the owner of the authentication (typically a User)
  4. InternalAPI security-context is allowed when the ADMIN role is present
  5. All else is denied

Thus, whenever an entity is accessed, it should be provided to the applicable WalletBaseServiceImpl.checkAuthentication() methods.

OAuth2 integration

There are following OAuth2 use cases supported:

  • OAuth2 grant type “client_credentials” (POST .../api/1_0_0/auth/oauth2login):
    For some requests it is necessary to be routed through a third party application, e.g. if such an application takes over the credit card tokenization. Such a third party application have to be authenticated with OAuth2 credentials (client-id and client-secret). In a success case the application gets a Bearer Token. This token have to be sent on each routed request together with the Token-Id which originally comes from the client. Such a Token-Id represents a consumer. It means the routed call will be executed on behalf of such a consumer with its authorizations.
  • OAuth2 grant type “password” (POST .../api/1_0_0/auth/oauth2login_user):
    A wallet user is able to obtain an OAuth2 access_token. The user have to authenticate with its own credentials and the OAuth2 clientId. Such a token can be used for all API calls.
  • OAuth2 grant type “implicit” (has no explicit API, is only internally usable with SYSTEM authorization).
    In such a case a system call generates a similar access_token as with grant type “password” for a user, but the user does not have to enter his credentials.
  • OAuth2 grant type “refresh_token” (POST .../api/1_0_0/auth/refresh_oauth2_access_token):
    An access_token with a grant type “password” can be issued together with a refresh_token. Such a refresh_token can be used to issue a new access_token without to prompt the user to enter his credentials again. In such a case the previous access_token will be invalided.
  • Per default all OAuth2 API calls are forbidden, it can be allowed with a corresponding DefaultApiRequestInfoProvider configuration