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

com.github.vzakharchenko.radius.password.UpdateRadiusPassword Maven / Gradle / Ivy

package com.github.vzakharchenko.radius.password;

import org.jboss.logging.Logger;
import org.keycloak.Config;
import org.keycloak.OAuth2Constants;
import org.keycloak.authentication.*;
import org.keycloak.common.util.Time;
import org.keycloak.credential.CredentialModel;
import org.keycloak.credential.CredentialProvider;
import org.keycloak.events.Details;
import org.keycloak.events.Errors;
import org.keycloak.events.EventBuilder;
import org.keycloak.events.EventType;
import org.keycloak.models.*;
import org.keycloak.services.validation.Validation;

import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static org.keycloak.events.Errors.PASSWORD_CONFIRM_ERROR;
import static org.keycloak.events.Errors.PASSWORD_MISSING;
import static org.keycloak.services.messages.Messages.MISSING_PASSWORD;
import static org.keycloak.services.messages.Messages.NOTMATCH_PASSWORD;


public class UpdateRadiusPassword implements RequiredActionProvider,
        RequiredActionFactory, DisplayTypeRequiredActionFactory {
    public static final String UPDATE_RADIUS_PASSWORD_ID = "UPDATE_RADIUS_PASSWORD";
    public static final String USERNAME = "username";
    public static final String RADIUS_UPDATE_PASSWORD = UPDATE_RADIUS_PASSWORD_ID;
    public static final String UPDATE_PASSWORD_ERROR = "UPDATE_PASSWORD_ERROR";
    private static final Logger LOGGER = Logger.getLogger(UpdateRadiusPassword.class);

    @Override
    public InitiatedActionSupport initiatedActionSupport() {
        return InitiatedActionSupport.SUPPORTED;
    }

    protected IRadiusCredentialProvider getProvider(RequiredActionContext context) {
        return
                (IRadiusCredentialProvider) context.getSession()
                        .getProvider(CredentialProvider.class,
                                RadiusCredentialProviderFactory.RADIUS_PROVIDER_ID);
    }

    @Override
    public void evaluateTriggers(RequiredActionContext context) {
        int daysToExpirePassword = context.getRealm().getPasswordPolicy()
                .getDaysToExpirePassword();
        if (daysToExpirePassword != -1) {
            IRadiusCredentialProvider passwordProvider = getProvider(context);
            CredentialModel password = passwordProvider
                    .getPassword(context.getRealm(), context.getUser());
            if (password != null) {
                if (password.getCreatedDate() == null) {
                    context.getUser().addRequiredAction(getId());
                    LOGGER.debug("User is required to update Mikrotik password");
                } else {
                    long timeElapsed = Time.toMillis(Time.currentTime()) - password
                            .getCreatedDate();
                    long timeToExpire = TimeUnit.DAYS.toMillis(daysToExpirePassword);

                    if (timeElapsed > timeToExpire) {
                        context.getUser().addRequiredAction(getId());
                        LOGGER.debug("User is required to update password");
                    }
                }
            }
        }
    }

    @Override
    public void requiredActionChallenge(RequiredActionContext context) {
        Response challenge = context.form()
                .setAttribute(USERNAME, context.getAuthenticationSession()
                        .getAuthenticatedUser().getUsername())
                .createResponse(UserModel.RequiredAction.UPDATE_PASSWORD);
        context.challenge(challenge);
    }

    protected EventBuilder createEvent(RequiredActionContext context,
                                       EventBuilder event) {
        return event.clone().event(EventType.UPDATE_PASSWORD_ERROR)
                .client(context.getAuthenticationSession().getClient())
                .user(context.getAuthenticationSession().getAuthenticatedUser())
                .detail(
                        UPDATE_PASSWORD_ERROR,
                        "Update Radius Server password error");
    }

    protected void commonResponse(RequiredActionContext context,
                                  EventBuilder errorEvent,
                                  String message,
                                  String eventMessage) {
        Response challenge = context.form()
                .setAttribute(USERNAME, context.getAuthenticationSession()
                        .getAuthenticatedUser().getUsername())
                .setError(message)
                .createResponse(UserModel.RequiredAction.UPDATE_PASSWORD);
        context.challenge(challenge);
        errorEvent.error(eventMessage);
    }

    protected void success(RequiredActionContext context,
                           String passwordNew) {
        RealmModel realm = context.getRealm();
        UserModel user = context.getUser();
        List credentials = context
                .getSession()
                .userCredentialManager()
                .getStoredCredentialsByType(realm,
                        user,
                        RadiusCredentialModel.TYPE);
        RadiusCredentialModel credentialModel = RadiusCredentialModel
                .createFromValues(passwordNew, user.getId());
        if (credentials.isEmpty()) {
            context
                    .getSession()
                    .userCredentialManager()
                    .createCredential(realm, user,
                            credentialModel);
        } else {
            context.getSession().userCredentialManager()
                    .updateCredential(realm, user,
                            credentialModel);
        }
        context.success();
    }

    protected void exceptionHandler(EventBuilder errorEvent,
                                    RequiredActionContext context,
                                    Exception e) {
        Object[] parameters = (e instanceof ModelException) ?
                ((ModelException) e).getParameters() :
                new Object[0];
        errorEvent.detail(Details.REASON, e.getMessage()).error(Errors.PASSWORD_REJECTED);
        Response challenge = context.form()
                .setAttribute(USERNAME, context
                        .getAuthenticationSession().getAuthenticatedUser().getUsername())
                .setError(e.getMessage(), parameters)
                .createResponse(UserModel.RequiredAction.UPDATE_PASSWORD);
        context.challenge(challenge);
    }


    @Override
    public void processAction(RequiredActionContext context) {
        EventBuilder event = context.getEvent();
        MultivaluedMap formData = context.getHttpRequest()
                .getDecodedFormParameters();
        event.event(EventType.UPDATE_PASSWORD);
        event.detail(
                RADIUS_UPDATE_PASSWORD,
                "Update Radius Server password");
        String passwordNew = formData.getFirst("password-new");
        String passwordConfirm = formData.getFirst("password-confirm");
        EventBuilder errorEvent = createEvent(context, event);
        if (Validation.isBlank(passwordNew)) {
            commonResponse(context, errorEvent, MISSING_PASSWORD, PASSWORD_MISSING);
        } else if (!passwordNew.equals(passwordConfirm)) {
            commonResponse(context, errorEvent, NOTMATCH_PASSWORD, PASSWORD_CONFIRM_ERROR);
        } else {
            try {
                success(context, passwordNew);
            } catch (Exception ape) {
                exceptionHandler(errorEvent, context, ape);
            }
        }
    }

    @Override
    public void close() {

    }

    @Override
    public RequiredActionProvider create(KeycloakSession session) {
        return this;
    }


    @Override
    public RequiredActionProvider createDisplay(KeycloakSession session, String displayType) {
        if (displayType == null) {
            return this;
        }
        if (!OAuth2Constants.DISPLAY_CONSOLE.equalsIgnoreCase(displayType)) {
            return null;
        }
        return ConsoleUpdateRadiusPassword.SINGLETON;
    }


    @Override
    public void init(Config.Scope config) {

    }

    @Override
    public void postInit(KeycloakSessionFactory factory) {

    }

    @Override
    public String getDisplayText() {
        return "Update Radius Password";
    }


    @Override
    public String getId() {
        return UPDATE_RADIUS_PASSWORD_ID;
    }

    @Override
    public boolean isOneTimeAction() {
        return true;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy