예제 #1
0
 protected AccessToken initToken(
     RealmModel realm,
     ClientModel client,
     UserModel user,
     UserSessionModel session,
     ClientSessionModel clientSession) {
   AccessToken token = new AccessToken();
   if (clientSession != null) token.clientSession(clientSession.getId());
   token.id(KeycloakModelUtils.generateId());
   token.subject(user.getId());
   token.audience(client.getClientId());
   token.issuedNow();
   token.issuedFor(client.getClientId());
   token.issuer(clientSession.getNote(OIDCLoginProtocol.ISSUER));
   if (session != null) {
     token.setSessionState(session.getId());
   }
   if (realm.getAccessTokenLifespan() > 0) {
     token.expiration(Time.currentTime() + realm.getAccessTokenLifespan());
   }
   Set<String> allowedOrigins = client.getWebOrigins();
   if (allowedOrigins != null) {
     token.setAllowedOrigins(allowedOrigins);
   }
   return token;
 }
예제 #2
0
 protected SAML2LogoutRequestBuilder createLogoutRequest(
     String logoutUrl, ClientSessionModel clientSession, ClientModel client) {
   // build userPrincipal with subject used at login
   SAML2LogoutRequestBuilder logoutBuilder =
       new SAML2LogoutRequestBuilder()
           .assertionExpiration(realm.getAccessCodeLifespan())
           .issuer(getResponseIssuer(realm))
           .sessionIndex(clientSession.getId())
           .userPrincipal(
               clientSession.getNote(SAML_NAME_ID), clientSession.getNote(SAML_NAME_ID_FORMAT))
           .destination(logoutUrl);
   return logoutBuilder;
 }
예제 #3
0
  private void initEvent(ClientSessionModel clientSession) {
    event
        .event(EventType.LOGIN)
        .client(clientSession.getClient())
        .user(clientSession.getUserSession().getUser())
        .session(clientSession.getUserSession().getId())
        .detail(Details.CODE_ID, clientSession.getId())
        .detail(Details.REDIRECT_URI, clientSession.getRedirectUri())
        .detail(
            Details.USERNAME,
            clientSession.getNote(AbstractUsernameFormAuthenticator.ATTEMPTED_USERNAME))
        .detail(Details.RESPONSE_TYPE, "code");

    UserSessionModel userSession = clientSession.getUserSession();

    if (userSession != null) {
      event.detail(Details.AUTH_METHOD, userSession.getAuthMethod());
      event.detail(Details.USERNAME, userSession.getLoginUsername());
      if (userSession.isRememberMe()) {
        event.detail(Details.REMEMBER_ME, "true");
      }
    }
  }
예제 #4
0
  public TokenValidation validateToken(
      KeycloakSession session,
      UriInfo uriInfo,
      ClientConnection connection,
      RealmModel realm,
      AccessToken oldToken,
      HttpHeaders headers)
      throws OAuthErrorException {
    UserModel user = session.users().getUserById(oldToken.getSubject(), realm);
    if (user == null) {
      throw new OAuthErrorException(
          OAuthErrorException.INVALID_GRANT, "Invalid refresh token", "Unknown user");
    }

    if (!user.isEnabled()) {
      throw new OAuthErrorException(
          OAuthErrorException.INVALID_GRANT, "User disabled", "User disabled");
    }

    UserSessionModel userSession =
        session.sessions().getUserSession(realm, oldToken.getSessionState());
    if (!AuthenticationManager.isSessionValid(realm, userSession)) {
      AuthenticationManager.backchannelLogout(
          session, realm, userSession, uriInfo, connection, headers, true);
      throw new OAuthErrorException(
          OAuthErrorException.INVALID_GRANT, "Session not active", "Session not active");
    }
    ClientSessionModel clientSession = null;
    for (ClientSessionModel clientSessionModel : userSession.getClientSessions()) {
      if (clientSessionModel.getId().equals(oldToken.getClientSession())) {
        clientSession = clientSessionModel;
        break;
      }
    }

    if (clientSession == null) {
      throw new OAuthErrorException(
          OAuthErrorException.INVALID_GRANT,
          "Client session not active",
          "Client session not active");
    }

    ClientModel client = clientSession.getClient();

    if (!client.getClientId().equals(oldToken.getIssuedFor())) {
      throw new OAuthErrorException(
          OAuthErrorException.INVALID_GRANT, "Unmatching clients", "Unmatching clients");
    }

    if (oldToken.getIssuedAt() < client.getNotBefore()) {
      throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Stale token");
    }
    if (oldToken.getIssuedAt() < realm.getNotBefore()) {
      throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Stale token");
    }

    // recreate token.
    Set<RoleModel> requestedRoles = TokenManager.getAccess(null, clientSession.getClient(), user);
    AccessToken newToken =
        createClientAccessToken(
            session, requestedRoles, realm, client, user, userSession, clientSession);
    verifyAccess(oldToken, newToken);

    return new TokenValidation(user, userSession, clientSession, newToken);
  }
예제 #5
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);
    }
  }
예제 #6
0
  /**
   * OAuth grant page. You should not invoked this directly!
   *
   * @param formData
   * @return
   */
  @Path("consent")
  @POST
  @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
  public Response processConsent(final MultivaluedMap<String, String> formData) {
    event.event(EventType.LOGIN).detail(Details.RESPONSE_TYPE, "code");

    if (!checkSsl()) {
      return ErrorPage.error(session, Messages.HTTPS_REQUIRED);
    }

    String code = formData.getFirst("code");

    ClientSessionCode accessCode = ClientSessionCode.parse(code, session, realm);
    if (accessCode == null || !accessCode.isValid(ClientSessionModel.Action.OAUTH_GRANT.name())) {
      event.error(Errors.INVALID_CODE);
      return ErrorPage.error(session, Messages.INVALID_ACCESS_CODE);
    }
    ClientSessionModel clientSession = accessCode.getClientSession();
    event.detail(Details.CODE_ID, clientSession.getId());

    String redirect = clientSession.getRedirectUri();
    UserSessionModel userSession = clientSession.getUserSession();
    UserModel user = userSession.getUser();
    ClientModel client = clientSession.getClient();

    event
        .client(client)
        .user(user)
        .detail(Details.RESPONSE_TYPE, "code")
        .detail(Details.REDIRECT_URI, redirect);

    event.detail(Details.AUTH_METHOD, userSession.getAuthMethod());
    event.detail(Details.USERNAME, userSession.getLoginUsername());
    if (userSession.isRememberMe()) {
      event.detail(Details.REMEMBER_ME, "true");
    }

    if (!AuthenticationManager.isSessionValid(realm, userSession)) {
      AuthenticationManager.backchannelLogout(
          session, realm, userSession, uriInfo, clientConnection, headers, true);
      event.error(Errors.INVALID_CODE);
      return ErrorPage.error(session, Messages.SESSION_NOT_ACTIVE);
    }
    event.session(userSession);

    if (formData.containsKey("cancel")) {
      LoginProtocol protocol =
          session.getProvider(LoginProtocol.class, clientSession.getAuthMethod());
      protocol.setRealm(realm).setHttpHeaders(headers).setUriInfo(uriInfo);
      event.error(Errors.REJECTED_BY_USER);
      return protocol.consentDenied(clientSession);
    }

    UserConsentModel grantedConsent = user.getConsentByClient(client.getId());
    if (grantedConsent == null) {
      grantedConsent = new UserConsentModel(client);
      user.addConsent(grantedConsent);
    }
    for (RoleModel role : accessCode.getRequestedRoles()) {
      grantedConsent.addGrantedRole(role);
    }
    for (ProtocolMapperModel protocolMapper : accessCode.getRequestedProtocolMappers()) {
      if (protocolMapper.isConsentRequired() && protocolMapper.getConsentText() != null) {
        grantedConsent.addGrantedProtocolMapper(protocolMapper);
      }
    }
    user.updateConsent(grantedConsent);

    event.detail(Details.CONSENT, Details.CONSENT_VALUE_CONSENT_GRANTED);
    event.success();

    return authManager.redirectAfterSuccessfulFlow(
        session, realm, userSession, clientSession, request, uriInfo, clientConnection);
  }
예제 #7
0
 public boolean verifyCode(String code) {
   if (!checkSsl()) {
     event.error(Errors.SSL_REQUIRED);
     response = ErrorPage.error(session, Messages.HTTPS_REQUIRED);
     return false;
   }
   if (!realm.isEnabled()) {
     event.error(Errors.REALM_DISABLED);
     response = ErrorPage.error(session, Messages.REALM_NOT_ENABLED);
     return false;
   }
   ClientSessionCode.ParseResult result = ClientSessionCode.parseResult(code, session, realm);
   clientCode = result.getCode();
   if (clientCode == null) {
     if (result.isClientSessionNotFound()) { // timeout
       try {
         ClientSessionModel clientSession =
             RestartLoginCookie.restartSession(session, realm, code);
         if (clientSession != null) {
           event
               .clone()
               .detail(Details.RESTART_AFTER_TIMEOUT, "true")
               .error(Errors.EXPIRED_CODE);
           response =
               processFlow(
                   null,
                   clientSession,
                   AUTHENTICATE_PATH,
                   realm.getBrowserFlow(),
                   Messages.LOGIN_TIMEOUT);
           return false;
         }
       } catch (Exception e) {
         logger.error("failed to parse RestartLoginCookie", e);
       }
     }
     event.error(Errors.INVALID_CODE);
     response = ErrorPage.error(session, Messages.INVALID_CODE);
     return false;
   }
   ClientSessionModel clientSession = clientCode.getClientSession();
   if (clientSession == null) {
     event.error(Errors.INVALID_CODE);
     response = ErrorPage.error(session, Messages.INVALID_CODE);
     return false;
   }
   event.detail(Details.CODE_ID, clientSession.getId());
   ClientModel client = clientSession.getClient();
   if (client == null) {
     event.error(Errors.CLIENT_NOT_FOUND);
     response = ErrorPage.error(session, Messages.UNKNOWN_LOGIN_REQUESTER);
     session.sessions().removeClientSession(realm, clientSession);
     return false;
   }
   if (!client.isEnabled()) {
     event.error(Errors.CLIENT_NOT_FOUND);
     response = ErrorPage.error(session, Messages.LOGIN_REQUESTER_NOT_ENABLED);
     session.sessions().removeClientSession(realm, clientSession);
     return false;
   }
   session.getContext().setClient(client);
   return true;
 }