Example #1
0
  protected boolean isLogoutPostBindingForClient(ClientSessionModel clientSession) {
    ClientModel client = clientSession.getClient();
    SamlClient samlClient = new SamlClient(client);
    String logoutPostUrl = client.getAttribute(SAML_SINGLE_LOGOUT_SERVICE_URL_POST_ATTRIBUTE);
    String logoutRedirectUrl =
        client.getAttribute(SAML_SINGLE_LOGOUT_SERVICE_URL_REDIRECT_ATTRIBUTE);

    if (logoutPostUrl == null) {
      // if we don't have a redirect uri either, return true and default to the admin url + POST
      // binding
      if (logoutRedirectUrl == null) return true;
      return false;
    }

    if (samlClient.forcePostBinding()) {
      return true; // configured to force a post binding and post binding logout url is not null
    }

    String bindingType = clientSession.getNote(SAML_BINDING);

    // if the login binding was POST, return true
    if (SAML_POST_BINDING.equals(bindingType)) return true;

    if (logoutRedirectUrl == null)
      return true; // we don't have a redirect binding url, so use post binding

    return false; // redirect binding
  }
Example #2
0
 @Override
 protected void verifySignature(SAMLDocumentHolder documentHolder, ClientModel client)
     throws VerificationException {
   SamlClient samlClient = new SamlClient(client);
   if (!samlClient.requiresClientSignature()) {
     return;
   }
   PublicKey publicKey = SamlProtocolUtils.getSignatureValidationKey(client);
   SamlProtocolUtils.verifyRedirectSignature(
       publicKey, uriInfo, GeneralConstants.SAML_REQUEST_KEY);
 }
Example #3
0
 private JaxrsSAML2BindingBuilder createBindingBuilder(SamlClient samlClient) {
   JaxrsSAML2BindingBuilder binding = new JaxrsSAML2BindingBuilder();
   if (samlClient.requiresRealmSignature()) {
     KeyManager.ActiveKey keys = session.keys().getActiveKey(realm);
     binding
         .signatureAlgorithm(samlClient.getSignatureAlgorithm())
         .signWith(keys.getPrivateKey(), keys.getPublicKey(), keys.getCertificate())
         .signDocument();
   }
   return binding;
 }
Example #4
0
  protected String getNameIdFormat(SamlClient samlClient, ClientSessionModel clientSession) {
    String nameIdFormat = clientSession.getNote(GeneralConstants.NAMEID_FORMAT);

    boolean forceFormat = samlClient.forceNameIDFormat();
    String configuredNameIdFormat = samlClient.getNameIDFormat();
    if ((nameIdFormat == null || forceFormat) && configuredNameIdFormat != null) {
      nameIdFormat = configuredNameIdFormat;
    }
    if (nameIdFormat == null) return SAML_DEFAULT_NAMEID_FORMAT;
    return nameIdFormat;
  }
Example #5
0
    protected Response logoutRequest(
        LogoutRequestType logoutRequest, ClientModel client, String relayState) {
      SamlClient samlClient = new SamlClient(client);
      // validate destination
      if (logoutRequest.getDestination() != null
          && !uriInfo.getAbsolutePath().equals(logoutRequest.getDestination())) {
        event.detail(Details.REASON, "invalid_destination");
        event.error(Errors.INVALID_SAML_LOGOUT_REQUEST);
        return ErrorPage.error(session, Messages.INVALID_REQUEST);
      }

      // authenticate identity cookie, but ignore an access token timeout as we're logging out
      // anyways.
      AuthenticationManager.AuthResult authResult =
          authManager.authenticateIdentityCookie(session, realm, false);
      if (authResult != null) {
        String logoutBinding = getBindingType();
        if ("true".equals(samlClient.forcePostBinding()))
          logoutBinding = SamlProtocol.SAML_POST_BINDING;
        String bindingUri = SamlProtocol.getLogoutServiceUrl(uriInfo, client, logoutBinding);
        UserSessionModel userSession = authResult.getSession();
        userSession.setNote(SamlProtocol.SAML_LOGOUT_BINDING_URI, bindingUri);
        if (samlClient.requiresRealmSignature()) {
          userSession.setNote(
              SamlProtocol.SAML_LOGOUT_SIGNATURE_ALGORITHM,
              samlClient.getSignatureAlgorithm().toString());
        }
        if (relayState != null)
          userSession.setNote(SamlProtocol.SAML_LOGOUT_RELAY_STATE, relayState);
        userSession.setNote(SamlProtocol.SAML_LOGOUT_REQUEST_ID, logoutRequest.getID());
        userSession.setNote(SamlProtocol.SAML_LOGOUT_BINDING, logoutBinding);
        userSession.setNote(
            SamlProtocol.SAML_LOGOUT_CANONICALIZATION, samlClient.getCanonicalizationMethod());
        userSession.setNote(
            AuthenticationManager.KEYCLOAK_LOGOUT_PROTOCOL, SamlProtocol.LOGIN_PROTOCOL);
        // remove client from logout requests
        for (ClientSessionModel clientSession : userSession.getClientSessions()) {
          if (clientSession.getClient().getId().equals(client.getId())) {
            clientSession.setAction(ClientSessionModel.Action.LOGGED_OUT.name());
          }
        }
        logger.debug("browser Logout");
        return authManager.browserLogout(
            session, realm, userSession, uriInfo, clientConnection, headers);
      } else if (logoutRequest.getSessionIndex() != null) {
        for (String sessionIndex : logoutRequest.getSessionIndex()) {
          ClientSessionModel clientSession =
              session.sessions().getClientSession(realm, sessionIndex);
          if (clientSession == null) continue;
          UserSessionModel userSession = clientSession.getUserSession();
          if (clientSession.getClient().getClientId().equals(client.getClientId())) {
            // remove requesting client from logout
            clientSession.setAction(ClientSessionModel.Action.LOGGED_OUT.name());

            // Remove also other clientSessions of this client as there could be more in this
            // UserSession
            if (userSession != null) {
              for (ClientSessionModel clientSession2 : userSession.getClientSessions()) {
                if (clientSession2.getClient().getId().equals(client.getId())) {
                  clientSession2.setAction(ClientSessionModel.Action.LOGGED_OUT.name());
                }
              }
            }
          }

          try {
            authManager.backchannelLogout(
                session, realm, userSession, uriInfo, clientConnection, headers, true);
          } catch (Exception e) {
            logger.warn("Failure with backchannel logout", e);
          }
        }
      }

      // default

      String logoutBinding = getBindingType();
      String logoutBindingUri = SamlProtocol.getLogoutServiceUrl(uriInfo, client, logoutBinding);
      String logoutRelayState = relayState;
      SAML2LogoutResponseBuilder builder = new SAML2LogoutResponseBuilder();
      builder.logoutRequestID(logoutRequest.getID());
      builder.destination(logoutBindingUri);
      builder.issuer(RealmsResource.realmBaseUrl(uriInfo).build(realm.getName()).toString());
      JaxrsSAML2BindingBuilder binding =
          new JaxrsSAML2BindingBuilder().relayState(logoutRelayState);
      if (samlClient.requiresRealmSignature()) {
        SignatureAlgorithm algorithm = samlClient.getSignatureAlgorithm();
        KeyManager.ActiveKey keys = session.keys().getActiveKey(realm);
        binding
            .signatureAlgorithm(algorithm)
            .signWith(keys.getPrivateKey(), keys.getPublicKey(), keys.getCertificate())
            .signDocument();
      }
      try {
        if (SamlProtocol.SAML_POST_BINDING.equals(logoutBinding)) {
          return binding.postBinding(builder.buildDocument()).response(logoutBindingUri);
        } else {
          return binding.redirectBinding(builder.buildDocument()).response(logoutBindingUri);
        }
      } catch (Exception e) {
        throw new RuntimeException(e);
      }
    }
Example #6
0
    protected Response loginRequest(
        String relayState, AuthnRequestType requestAbstractType, ClientModel client) {
      SamlClient samlClient = new SamlClient(client);
      // validate destination
      if (requestAbstractType.getDestination() != null
          && !uriInfo.getAbsolutePath().equals(requestAbstractType.getDestination())) {
        event.detail(Details.REASON, "invalid_destination");
        event.error(Errors.INVALID_SAML_AUTHN_REQUEST);
        return ErrorPage.error(session, Messages.INVALID_REQUEST);
      }
      String bindingType = getBindingType(requestAbstractType);
      if (samlClient.forcePostBinding()) bindingType = SamlProtocol.SAML_POST_BINDING;
      String redirect = null;
      URI redirectUri = requestAbstractType.getAssertionConsumerServiceURL();
      if (redirectUri != null && !"null".equals(redirectUri)) { // "null" is for testing purposes
        redirect = RedirectUtils.verifyRedirectUri(uriInfo, redirectUri.toString(), realm, client);
      } else {
        if (bindingType.equals(SamlProtocol.SAML_POST_BINDING)) {
          redirect = client.getAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_POST_ATTRIBUTE);
        } else {
          redirect =
              client.getAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_REDIRECT_ATTRIBUTE);
        }
        if (redirect == null) {
          redirect = client.getManagementUrl();
        }
      }

      if (redirect == null) {
        event.error(Errors.INVALID_REDIRECT_URI);
        return ErrorPage.error(session, Messages.INVALID_REDIRECT_URI);
      }

      ClientSessionModel clientSession = session.sessions().createClientSession(realm, client);
      clientSession.setAuthMethod(SamlProtocol.LOGIN_PROTOCOL);
      clientSession.setRedirectUri(redirect);
      clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
      clientSession.setNote(SamlProtocol.SAML_BINDING, bindingType);
      clientSession.setNote(GeneralConstants.RELAY_STATE, relayState);
      clientSession.setNote(SamlProtocol.SAML_REQUEST_ID, requestAbstractType.getID());

      // Handle NameIDPolicy from SP
      NameIDPolicyType nameIdPolicy = requestAbstractType.getNameIDPolicy();
      if (nameIdPolicy != null && !samlClient.forceNameIDFormat()) {
        String nameIdFormat = nameIdPolicy.getFormat().toString();
        // TODO: Handle AllowCreate too, relevant for persistent NameID.
        if (isSupportedNameIdFormat(nameIdFormat)) {
          clientSession.setNote(GeneralConstants.NAMEID_FORMAT, nameIdFormat);
        } else {
          event.detail(Details.REASON, "unsupported_nameid_format");
          event.error(Errors.INVALID_SAML_AUTHN_REQUEST);
          return ErrorPage.error(session, Messages.UNSUPPORTED_NAME_ID_FORMAT);
        }
      }

      // Reading subject/nameID in the saml request
      SubjectType subject = requestAbstractType.getSubject();
      if (subject != null) {
        SubjectType.STSubType subType = subject.getSubType();
        if (subType != null) {
          BaseIDAbstractType baseID = subject.getSubType().getBaseID();
          if (baseID != null && baseID instanceof NameIDType) {
            NameIDType nameID = (NameIDType) baseID;
            clientSession.setNote(OIDCLoginProtocol.LOGIN_HINT_PARAM, nameID.getValue());
          }
        }
      }

      return newBrowserAuthentication(
          clientSession, requestAbstractType.isIsPassive(), redirectToAuthentication);
    }
Example #7
0
  @Override
  public Response authenticated(UserSessionModel userSession, ClientSessionCode accessCode) {
    ClientSessionModel clientSession = accessCode.getClientSession();
    ClientModel client = clientSession.getClient();
    SamlClient samlClient = new SamlClient(client);
    String requestID = clientSession.getNote(SAML_REQUEST_ID);
    String relayState = clientSession.getNote(GeneralConstants.RELAY_STATE);
    String redirectUri = clientSession.getRedirectUri();
    String responseIssuer = getResponseIssuer(realm);
    String nameIdFormat = getNameIdFormat(samlClient, clientSession);
    String nameId = getNameId(nameIdFormat, clientSession, userSession);

    // save NAME_ID and format in clientSession as they may be persistent or transient or email and
    // not username
    // we'll need to send this back on a logout
    clientSession.setNote(SAML_NAME_ID, nameId);
    clientSession.setNote(SAML_NAME_ID_FORMAT, nameIdFormat);

    SAML2LoginResponseBuilder builder = new SAML2LoginResponseBuilder();
    builder
        .requestID(requestID)
        .destination(redirectUri)
        .issuer(responseIssuer)
        .assertionExpiration(realm.getAccessCodeLifespan())
        .subjectExpiration(realm.getAccessTokenLifespan())
        .sessionIndex(clientSession.getId())
        .requestIssuer(clientSession.getClient().getClientId())
        .nameIdentifier(nameIdFormat, nameId)
        .authMethod(JBossSAMLURIConstants.AC_UNSPECIFIED.get());
    if (!samlClient.includeAuthnStatement()) {
      builder.disableAuthnStatement(true);
    }

    List<ProtocolMapperProcessor<SAMLAttributeStatementMapper>> attributeStatementMappers =
        new LinkedList<>();
    List<ProtocolMapperProcessor<SAMLLoginResponseMapper>> loginResponseMappers =
        new LinkedList<>();
    ProtocolMapperProcessor<SAMLRoleListMapper> roleListMapper = null;

    Set<ProtocolMapperModel> mappings = accessCode.getRequestedProtocolMappers();
    for (ProtocolMapperModel mapping : mappings) {

      ProtocolMapper mapper =
          (ProtocolMapper)
              session
                  .getKeycloakSessionFactory()
                  .getProviderFactory(ProtocolMapper.class, mapping.getProtocolMapper());
      if (mapper == null) continue;
      if (mapper instanceof SAMLAttributeStatementMapper) {
        attributeStatementMappers.add(
            new ProtocolMapperProcessor<SAMLAttributeStatementMapper>(
                (SAMLAttributeStatementMapper) mapper, mapping));
      }
      if (mapper instanceof SAMLLoginResponseMapper) {
        loginResponseMappers.add(
            new ProtocolMapperProcessor<SAMLLoginResponseMapper>(
                (SAMLLoginResponseMapper) mapper, mapping));
      }
      if (mapper instanceof SAMLRoleListMapper) {
        roleListMapper =
            new ProtocolMapperProcessor<SAMLRoleListMapper>((SAMLRoleListMapper) mapper, mapping);
      }
    }

    Document samlDocument = null;
    try {
      ResponseType samlModel = builder.buildModel();
      final AttributeStatementType attributeStatement =
          populateAttributeStatements(
              attributeStatementMappers, session, userSession, clientSession);
      populateRoles(roleListMapper, session, userSession, clientSession, attributeStatement);

      // SAML Spec 2.7.3 AttributeStatement must contain one or more Attribute or EncryptedAttribute
      if (attributeStatement.getAttributes().size() > 0) {
        AssertionType assertion = samlModel.getAssertions().get(0).getAssertion();
        assertion.addStatement(attributeStatement);
      }

      samlModel =
          transformLoginResponse(
              loginResponseMappers, samlModel, session, userSession, clientSession);
      samlDocument = builder.buildDocument(samlModel);
    } catch (Exception e) {
      logger.error("failed", e);
      return ErrorPage.error(session, Messages.FAILED_TO_PROCESS_RESPONSE);
    }

    JaxrsSAML2BindingBuilder bindingBuilder = new JaxrsSAML2BindingBuilder();
    bindingBuilder.relayState(relayState);

    KeyManager keyManager = session.keys();
    KeyManager.ActiveKey keys = keyManager.getActiveKey(realm);

    if (samlClient.requiresRealmSignature()) {
      String canonicalization = samlClient.getCanonicalizationMethod();
      if (canonicalization != null) {
        bindingBuilder.canonicalizationMethod(canonicalization);
      }
      bindingBuilder
          .signatureAlgorithm(samlClient.getSignatureAlgorithm())
          .signWith(keys.getPrivateKey(), keys.getPublicKey(), keys.getCertificate())
          .signDocument();
    }
    if (samlClient.requiresAssertionSignature()) {
      String canonicalization = samlClient.getCanonicalizationMethod();
      if (canonicalization != null) {
        bindingBuilder.canonicalizationMethod(canonicalization);
      }
      bindingBuilder
          .signatureAlgorithm(samlClient.getSignatureAlgorithm())
          .signWith(keys.getPrivateKey(), keys.getPublicKey(), keys.getCertificate())
          .signAssertions();
    }
    if (samlClient.requiresEncryption()) {
      PublicKey publicKey = null;
      try {
        publicKey = SamlProtocolUtils.getEncryptionValidationKey(client);
      } catch (Exception e) {
        logger.error("failed", e);
        return ErrorPage.error(session, Messages.FAILED_TO_PROCESS_RESPONSE);
      }
      bindingBuilder.encrypt(publicKey);
    }
    try {
      return buildAuthenticatedResponse(clientSession, redirectUri, samlDocument, bindingBuilder);
    } catch (Exception e) {
      logger.error("failed", e);
      return ErrorPage.error(session, Messages.FAILED_TO_PROCESS_RESPONSE);
    }
  }
Example #8
0
 protected boolean isPostBinding(ClientSessionModel clientSession) {
   ClientModel client = clientSession.getClient();
   SamlClient samlClient = new SamlClient(client);
   return SamlProtocol.SAML_POST_BINDING.equals(clientSession.getNote(SamlProtocol.SAML_BINDING))
       || samlClient.forcePostBinding();
 }