/**
   * Create user identity token based on an issued token
   *
   * @param ep
   * @param senderNonce
   * @param issuedIdentityToken
   * @return user identity token
   * @throws ServiceResultException if endpoint or the stack doesn't support UserName token policy
   */
  public static UserIdentityToken createIssuedIdentityToken(
      EndpointDescription ep, byte[] senderNonce, byte[] issuedIdentityToken)
      throws ServiceResultException {
    UserTokenPolicy policy = ep.findUserTokenPolicy(UserTokenType.IssuedToken);
    if (policy == null)
      throw new ServiceResultException(
          StatusCodes.Bad_IdentityTokenRejected, "IssuedToken not supported");
    String securityPolicyUri = policy.getSecurityPolicyUri();
    if (securityPolicyUri == null) securityPolicyUri = ep.getSecurityPolicyUri();
    SecurityPolicy securityPolicy = SecurityPolicy.getSecurityPolicy(securityPolicyUri);
    if (securityPolicy == null) securityPolicy = SecurityPolicy.NONE;
    IssuedIdentityToken token = new IssuedIdentityToken();
    token.setTokenData(issuedIdentityToken);

    // Encrypt the token
    SecurityAlgorithm algorithmUri = securityPolicy.getAsymmetricEncryptionAlgorithm();
    if (algorithmUri == null) algorithmUri = SecurityAlgorithm.RsaOaep;
    try {
      Cipher cipher = Cipher.getInstance(algorithmUri.getStandardName());
      Cert serverCert = new Cert(ep.getServerCertificate());
      cipher.init(Cipher.ENCRYPT_MODE, serverCert.getCertificate());
      byte[] tokenData = issuedIdentityToken;
      if (senderNonce != null)
        tokenData =
            ByteBufferUtils.concatenate(
                toArray(issuedIdentityToken.length + senderNonce.length),
                issuedIdentityToken,
                senderNonce);
      token.setTokenData(cipher.doFinal(tokenData));
      token.setEncryptionAlgorithm(algorithmUri.getUri());

    } catch (InvalidKeyException e) {
      // Server certificate does not have encrypt usage
      throw new ServiceResultException(
          StatusCodes.Bad_CertificateInvalid,
          "Server certificate in endpoint is invalid: " + e.getMessage());
    } catch (IllegalBlockSizeException e) {
      throw new ServiceResultException(
          StatusCodes.Bad_SecurityPolicyRejected, e.getClass().getName() + ":" + e.getMessage());
    } catch (BadPaddingException e) {
      throw new ServiceResultException(
          StatusCodes.Bad_CertificateInvalid,
          "Server certificate in endpoint is invalid: " + e.getMessage());
    } catch (NoSuchAlgorithmException e) {
      throw new ServiceResultException(StatusCodes.Bad_InternalError, e);
    } catch (NoSuchPaddingException e) {
      throw new ServiceResultException(StatusCodes.Bad_InternalError, e);
    }

    return token;
  }
  /**
   * Create user identity token based on username and password
   *
   * @param ep
   * @param username
   * @param password
   * @return user identity token
   * @throws ServiceResultException if endpoint or the stack doesn't support UserName token policy
   */
  public static UserIdentityToken createUserNameIdentityToken(
      EndpointDescription ep, byte[] senderNonce, String username, String password)
      throws ServiceResultException {
    UserTokenPolicy policy = ep.findUserTokenPolicy(UserTokenType.UserName);
    if (policy == null)
      throw new ServiceResultException(
          StatusCodes.Bad_IdentityTokenRejected, "UserName not supported");
    String securityPolicyUri = policy.getSecurityPolicyUri();
    if (securityPolicyUri == null) securityPolicyUri = ep.getSecurityPolicyUri();
    SecurityPolicy securityPolicy = SecurityPolicy.getSecurityPolicy(securityPolicyUri);
    if (securityPolicy == null) securityPolicy = SecurityPolicy.NONE;
    UserNameIdentityToken token = new UserNameIdentityToken();

    token.setUserName(username);
    token.setPolicyId(policy.getPolicyId());

    // Encrypt the password, unless no security is defined
    SecurityAlgorithm algorithm = securityPolicy.getAsymmetricEncryptionAlgorithm();
    byte[] pw = password.getBytes(BinaryEncoder.UTF8);
    if (algorithm == null) token.setPassword(pw);
    else
      try {
        Cert serverCert = new Cert(ep.getServerCertificate());
        if (senderNonce != null)
          pw =
              ByteBufferUtils.concatenate(toArray(pw.length + senderNonce.length), pw, senderNonce);
        else pw = ByteBufferUtils.concatenate(toArray(pw.length), pw);
        pw = CryptoUtil.asymmEncrypt(pw, serverCert.getCertificate().getPublicKey(), algorithm);
        token.setPassword(pw);

      } catch (InvalidKeyException e) {
        // Server certificate does not have encrypt usage
        throw new ServiceResultException(
            StatusCodes.Bad_CertificateInvalid,
            "Server certificate in endpoint is invalid: " + e.getMessage());
      } catch (IllegalBlockSizeException e) {
        throw new ServiceResultException(
            StatusCodes.Bad_SecurityPolicyRejected, e.getClass().getName() + ":" + e.getMessage());
      } catch (BadPaddingException e) {
        throw new ServiceResultException(
            StatusCodes.Bad_CertificateInvalid,
            "Server certificate in endpoint is invalid: " + e.getMessage());
      } catch (NoSuchAlgorithmException e) {
        throw new ServiceResultException(StatusCodes.Bad_InternalError, e);
      } catch (NoSuchPaddingException e) {
        throw new ServiceResultException(StatusCodes.Bad_InternalError, e);
      }
    token.setEncryptionAlgorithm(algorithm.getUri());

    return token;
  }
  public static X509IdentityToken createX509IdentityToken(
      EndpointDescription ep,
      byte[] serverNonce,
      Cert certificate,
      PrivateKey key,
      SignatureData signatureData)
      throws ServiceResultException {
    if (signatureData == null)
      throw new NullPointerException("signatureData must be defined (will be filled in)");
    UserTokenPolicy policy = ep.findUserTokenPolicy(UserTokenType.Certificate);
    if (policy == null)
      throw new ServiceResultException(
          StatusCodes.Bad_IdentityTokenRejected, "Certificate UserTokenType is not supported");

    X509IdentityToken token = new X509IdentityToken(policy.getPolicyId(), certificate.getEncoded());

    String securityPolicyUri = policy.getSecurityPolicyUri();
    if (securityPolicyUri == null) securityPolicyUri = ep.getSecurityPolicyUri();
    SecurityPolicy securityPolicy = SecurityPolicy.getSecurityPolicy(securityPolicyUri);
    Cert serverCert = new Cert(ep.getServerCertificate());
    if ((securityPolicy != null) && (serverCert != null))
      try {
        // Create a Signature object and initialize it with the private
        // key
        Signature signature =
            Signature.getInstance(
                securityPolicy.getAsymmetricSignatureAlgorithm().getTransformation());
        signature.initSign(key);

        signature.update(serverCert.getEncoded());
        signature.update(serverNonce);

        signatureData.setSignature(signature.sign());
        signatureData.setAlgorithm(securityPolicy.getAsymmetricSignatureAlgorithm().getUri());

      } catch (NoSuchAlgorithmException e) {
        throw new ServiceResultException(
            StatusCodes.Bad_SecurityChecksFailed, "Signature generation failed: " + e.getMessage());
      } catch (InvalidKeyException e) {
        // Server certificate does not have encrypt usage
        throw new ServiceResultException(
            StatusCodes.Bad_CertificateInvalid,
            "Server certificate in endpoint is invalid: " + e.getMessage());
      } catch (SignatureException e) {
        throw new ServiceResultException(
            StatusCodes.Bad_SecurityChecksFailed, "Signature generation failed: " + e.getMessage());
      }
    return token;
  }
 /**
  * Selects all endpoints that conform to given message security mode
  *
  * @param searchSet
  * @param policy
  * @return A subset of searchSet whose elements use given message security mode
  */
 public static EndpointDescription[] selectBySecurityPolicy(
     EndpointDescription[] searchSet, SecurityPolicy policy) {
   List<EndpointDescription> result = new ArrayList<EndpointDescription>();
   for (EndpointDescription d : searchSet)
     if (ObjectUtils.objectEquals(d.getSecurityPolicyUri(), policy.getPolicyUri())) result.add(d);
   return result.toArray(new EndpointDescription[result.size()]);
 }
 /**
  * Filter endpoints by various criteria
  *
  * @param searchSet set of endpoints
  * @param url filter by url (inclusive, case insensitive) or null
  * @param protocol filter by protocol (inclusive) or null
  * @param mode filter by mode or null
  * @param policy filter by policy or null
  * @return filtered endpoints
  */
 public static EndpointDescription[] select(
     EndpointDescription[] searchSet,
     String url,
     String protocol,
     MessageSecurityMode mode,
     SecurityPolicy policy,
     byte[] serverCertificate) {
   List<EndpointDescription> result = new ArrayList<EndpointDescription>();
   for (EndpointDescription d : searchSet) {
     final String endpointUrl =
         d.getEndpointUrl() == null ? null : d.getEndpointUrl().toLowerCase();
     if (endpointUrl == null) continue;
     if (protocol != null && !endpointUrl.startsWith(protocol.toLowerCase())) continue;
     if (url != null && !ObjectUtils.objectEquals(endpointUrl, url.toLowerCase())) continue;
     if (mode != null && !ObjectUtils.objectEquals(d.getSecurityMode(), mode)) continue;
     if (policy != null
         && !ObjectUtils.objectEquals(d.getSecurityPolicyUri(), policy.getPolicyUri())) continue;
     if (serverCertificate != null && !Arrays.equals(serverCertificate, d.getServerCertificate()))
       continue;
     result.add(d);
   }
   return result.toArray(new EndpointDescription[result.size()]);
 }