All Downloads are FREE. Search and download functionalities are using the official Maven repository.

se.swedenconnect.signservice.engine.session.EngineContext Maven / Gradle / Ivy

/*
 * Copyright 2022-2024 Sweden Connect
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package se.swedenconnect.signservice.engine.session;

import java.util.Objects;
import java.util.Optional;
import java.util.UUID;

import lombok.extern.slf4j.Slf4j;
import se.swedenconnect.signservice.authn.IdentityAssertion;
import se.swedenconnect.signservice.context.DefaultSignServiceContext;
import se.swedenconnect.signservice.context.SignServiceContext;
import se.swedenconnect.signservice.protocol.SignRequestMessage;

/**
 * The {@code EngineContext} is a wrapper for the {@link SignServiceContext} that declares methods for context elements
 * that are used by the SignService engine.
 */
@Slf4j
public class EngineContext {

  /** Prefix for all context values. */
  private static final String PREFIX = EngineContext.class.getPackageName();

  /** Key for storing the state. */
  private static final String STATE_KEY = PREFIX + ".State";

  /** Key for storing the SignRequest message. */
  private static final String SIGN_REQUEST_KEY = PREFIX + ".SignRequest";

  /** Key for storing the identity assertion. */
  private static final String ASSERTION_KEY = PREFIX + ".IdentityAssertion";

  /** Key for storing whether a sign message was displayed. */
  private static final String SIGN_MESSAGE_DISPLAYED_KEY = PREFIX + ".SignMessageDisplayed";

  /** The wrapped context. */
  private SignServiceContext context;

  /**
   * Constructor.
   *
   * @param context the context that we wrap
   */
  public EngineContext(final SignServiceContext context) {
    this.context = Objects.requireNonNull(context, "context must not be null");
    if (!this.isActive()) {
      throw new IllegalStateException("Invalid context - it is not valid");
    }
  }

  /**
   * Creates and initializes a new {@link SignServiceContext} object.
   *
   * @return a SignServiceContext object
   */
  public static SignServiceContext createSignServiceContext() {
    final SignServiceContext context = new DefaultSignServiceContext(UUID.randomUUID().toString());
    log.debug("A SignServiceContext with ID '{}' was created", context.getId());

    // Initialize
    context.put(STATE_KEY, SignOperationState.NEW);
    return context;
  }

  /**
   * Marks the context as non-active, i.e., terminated.
   */
  public void terminateContext() {
    this.updateState(SignOperationState.TERMINATED);
  }

  /**
   * Will reset the context to a new context.
   */
  public void resetContext() {
    this.context = createSignServiceContext();
  }

  /**
   * Gets the ID of the wrapped SignService context.
   *
   * @return the ID
   */
  public String getId() {
    return this.context.getId();
  }

  /**
   * Gets the wrapped context.
   *
   * @return the SignService context
   */
  public SignServiceContext getContext() {
    return this.isActive() ? this.context : null;
  }

  /**
   * Gets the operation state.
   *
   * @return the state
   */
  public SignOperationState getState() {
    return Optional.ofNullable(this.context.get(STATE_KEY, SignOperationState.class))
        .orElseThrow(() -> new IllegalStateException("No SignService state available"));
  }

  /**
   * Updates the operation state.
   *
   * @param newState the new state to set
   * @throws IllegalStateException if an illegal state transition is performed
   */
  public void updateState(final SignOperationState newState) throws IllegalStateException {
    final SignOperationState currentState = this.getState();

    if (newState == SignOperationState.NEW) {
      throw new IllegalStateException("Illegal state transition - Cannot set state to NEW");
    }
    if (currentState == SignOperationState.TERMINATED && newState != SignOperationState.TERMINATED) {
      throw new IllegalStateException("Illegal state transition - State is terminated");
    }
    if (currentState == SignOperationState.SIGNING && newState == SignOperationState.AUTHN_ONGOING) {
      throw new IllegalStateException("Illegal state transition - Cannot go backwards in state transitions");
    }
    this.context.put(STATE_KEY, Objects.requireNonNull(newState, "Supplied state must not be null"));
  }

  /**
   * Adds a {@link SignRequestMessage} to the context.
   *
   * @param signRequest the SignRequest to add
   */
  public void putSignRequest(final SignRequestMessage signRequest) {
    this.context.put(SIGN_REQUEST_KEY,
        Objects.requireNonNull(signRequest, "signRequest must not be null"));
  }

  /**
   * Gets the {@link SignRequestMessage} from the context.
   *
   * @return the SignRequest
   */
  public SignRequestMessage getSignRequest() {
    return this.context.get(SIGN_REQUEST_KEY, SignRequestMessage.class);
  }

  /**
   * Adds a {@link IdentityAssertion} to the context.
   *
   * @param identityAssertion the identity assertion to add
   */
  public void putIdentityAssertion(final IdentityAssertion identityAssertion) {
    this.context.put(ASSERTION_KEY,
        Objects.requireNonNull(identityAssertion, "identityAssertion must not be null"));
  }

  /**
   * Gets the {@link IdentityAssertion} from the context.
   *
   * @return the identity assertion
   */
  public IdentityAssertion getIdentityAssertion() {
    return this.context.get(ASSERTION_KEY, IdentityAssertion.class);
  }

  /**
   * Adds whether the SignMessage was displayed.
   *
   * @param signMessageDisplayed whether SignMessage was displayed
   */
  public void putSignMessageDisplayed(final Boolean signMessageDisplayed) {
    this.context.put(SIGN_MESSAGE_DISPLAYED_KEY,
        Objects.requireNonNull(signMessageDisplayed, "signMessageDisplayed must not be null"));
  }

  /**
   * Gets whether the SignMessage was displayed.
   *
   * @return whether the SignMessage was displayed
   */
  public Boolean getSignMessageDisplayed() {
    return this.context.get(SIGN_MESSAGE_DISPLAYED_KEY, Boolean.class);
  }

  /**
   * Predicate that tells whether this context is active or not
   *
   * @return true if the context is active and false otherwise
   */
  private boolean isActive() {
    return this.getState() != SignOperationState.TERMINATED;
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy