Skip to content

Commit

Permalink
reworked midpoint principal to identity recovery service while identi…
Browse files Browse the repository at this point in the history
…ty recovery flow; identity recovery page works now with a list of recovered users taken from CorrelationModuleAuthentication
  • Loading branch information
KaterynaHonchar committed Aug 18, 2023
1 parent cd03a91 commit 382145a
Show file tree
Hide file tree
Showing 9 changed files with 186 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public class PageArchetypeSelection extends PageAbstractAuthenticationModule<Arc

private final IModel<String> archetypeOidModel = Model.of();

private LoadableDetachableModel<ArchetypeSelectionModuleAuthentication> archetypeSelectionModuleModel;
private LoadableModel<ArchetypeSelectionModuleAuthentication> archetypeSelectionModuleModel;
private LoadableModel<List<Tile<ArchetypeType>>> tilesModel;

public PageArchetypeSelection() {
Expand All @@ -76,7 +76,7 @@ protected void onInitialize() {
}

protected void initModels() {
archetypeSelectionModuleModel = new LoadableDetachableModel<>() {
archetypeSelectionModuleModel = new LoadableModel<>() {
@Serial private static final long serialVersionUID = 1L;

@Override
Expand All @@ -85,7 +85,7 @@ protected ArchetypeSelectionModuleAuthentication load() {
}
};

tilesModel = new LoadableModel<List<Tile<ArchetypeType>>>() {
tilesModel = new LoadableModel<List<Tile<ArchetypeType>>>(false) {
@Override
protected List<Tile<ArchetypeType>> load() {
return loadTilesList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@
<html xmlns:wicket="http://wicket.apache.org">
<body>
<wicket:extend>
<div wicket:id="loginNamePanel" class="user-panel info-box my-3 pb-2 d-flex justify-content-start align-items-center">
<div class="image">
<img wicket:id="photo" class="user-image img-circle elevation-2"/>
</div>
<div class="info">
<div class="text-lg" wicket:id="loginName"/>
<div wicket:id="recoveredIdentities">
<div wicket:id="loginNamePanel" class="user-panel info-box my-3 pb-2 d-flex justify-content-start align-items-center">
<div class="image">
<img wicket:id="photo" class="user-image img-circle elevation-2"/>
</div>
<div class="info">
<div class="text-lg" wicket:id="loginName"/>
</div>
</div>
</div>
<div class="d-flex flex-column justify-content-start mt-5 col-12">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@

package com.evolveum.midpoint.gui.impl.page.lostusername;

import com.evolveum.midpoint.authentication.api.AuthenticationModuleState;
import com.evolveum.midpoint.authentication.api.config.CorrelationModuleAuthentication;
import com.evolveum.midpoint.gui.api.model.LoadableModel;
import com.evolveum.midpoint.gui.api.util.LocalizationUtil;
import com.evolveum.midpoint.gui.api.util.WebComponentUtil;
import com.evolveum.midpoint.prism.ItemDefinition;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.security.api.MidPointPrincipal;

import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
Expand All @@ -33,6 +35,7 @@
import org.apache.wicket.model.Model;
import org.apache.wicket.request.resource.AbstractResource;
import org.apache.wicket.request.resource.ByteArrayResource;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;

import com.evolveum.midpoint.authentication.api.authorization.AuthorizationAction;
Expand All @@ -48,7 +51,9 @@
import java.io.Serial;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

@PageDescriptor(
urls = {
Expand All @@ -67,13 +72,15 @@ public class PageIdentityRecovery extends AbstractPageLogin {
private static final Trace LOGGER = TraceManager.getTrace(PageIdentityRecovery.class);
private static final String OPERATION_GET_SECURITY_POLICY = DOT_CLASS + "getSecurityPolicy";

private static final String ID_RECOVERED_IDENTITIES = "recoveredIdentities";
private static final String ID_LOGIN_NAME_PANEL = "loginNamePanel";
private static final String ID_LOGIN_NAME = "loginName";
private static final String ID_PHOTO = "photo";
private static final String ID_CONFIGURED_ITEMS_PANEL = "configuredItemsPanel";
private static final String ID_ITEM_NAME = "itemName";
private static final String ID_ITEM_VALUE = "itemValue";

private LoadableModel<List<UserType>> recoveredIdentitiesModel;
private LoadableModel<List<ItemPathType>> configuredItemsModel;


Expand All @@ -89,22 +96,36 @@ protected boolean isBackButtonVisible() {

@Override
protected void initCustomLayout() {
WebMarkupContainer loginNamePanel = new WebMarkupContainer(ID_LOGIN_NAME_PANEL);
loginNamePanel.setOutputMarkupId(true);
loginNamePanel.add(new VisibleBehaviour(() -> !configuredItemsExist()));
add(loginNamePanel);
ListView<UserType> recoveredIdentitiesPanel = new ListView<>(ID_RECOVERED_IDENTITIES, recoveredIdentitiesModel) {
@Override
protected void populateItem(ListItem<UserType> item) {
WebMarkupContainer loginNamePanel = new WebMarkupContainer(ID_LOGIN_NAME_PANEL);
loginNamePanel.setOutputMarkupId(true);
// loginNamePanel.add(new VisibleBehaviour(() -> isSingleRecoveredIdentity() && !configuredItemsExist()));
item.add(loginNamePanel);

NonCachingImage img = new NonCachingImage(ID_PHOTO, getImageResource());
loginNamePanel.add(img);
NonCachingImage img = new NonCachingImage(ID_PHOTO, getImageResource(item.getModelObject()));
loginNamePanel.add(img);

Label label = new Label(ID_LOGIN_NAME, getAuthorizedUserLoginNameModel());
label.add(new VisibleBehaviour(this::isUserFound));
loginNamePanel.add(label);
Label label = new Label(ID_LOGIN_NAME, getAuthorizedUserLoginNameModel(item.getModelObject()));
loginNamePanel.add(label);
}
};
recoveredIdentitiesPanel.setOutputMarkupId(true);
add(recoveredIdentitiesPanel);

initConfiguredItemsPanel();
}

private void initModels() {
recoveredIdentitiesModel = new LoadableModel<>() {
@Serial private static final long serialVersionUID = 1L;

@Override
protected List<UserType> load() {
return getRecoveredIdentities();
}
};
configuredItemsModel = new LoadableModel<>() {
@Serial private static final long serialVersionUID = 1L;

Expand All @@ -118,10 +139,15 @@ protected List<ItemPathType> load() {
private List<ItemPathType> loadConfiguredItemPathList() {
List<ItemPathType> configuredItems = new ArrayList<>();

if (!isSingleRecoveredIdentity()) {
return configuredItems;
}

var user = getRecoveredIdentities().get(0);
var task = createSimpleTask(OPERATION_GET_SECURITY_POLICY);
var result = new OperationResult(OPERATION_GET_SECURITY_POLICY);
try {
var securityPolicy = getModelInteractionService().getSecurityPolicy(getMidpointPrincipal().getFocusPrismObject(),
var securityPolicy = getModelInteractionService().getSecurityPolicy(user.asPrismObject(),
getMidpointAuthentication().getArchetypeOid(), task, result);
var identityRecoveryConfig = securityPolicy.getIdentityRecovery();
configuredItems = identityRecoveryConfig.getItemToDisplay();
Expand All @@ -132,14 +158,14 @@ private List<ItemPathType> loadConfiguredItemPathList() {
}

private boolean configuredItemsExist() {
return configuredItemsModel != null && CollectionUtils.isNotEmpty(configuredItemsModel.getObject());
return false; //todo fix
// return configuredItemsModel != null && CollectionUtils.isNotEmpty(configuredItemsModel.getObject());
}

private AbstractResource getImageResource() {
private AbstractResource getImageResource(UserType user) {
byte[] photo = null;
if (isUserFound()) {
var guiProfile = getPrincipal().getCompiledGuiProfile();
photo = guiProfile.getJpegPhoto();
if (user != null) {
photo = user.getJpegPhoto();
}
if (photo == null) {
URL defaultImage = this.getClass().getClassLoader().getResource("static/img/placeholder.png");
Expand All @@ -155,10 +181,8 @@ private AbstractResource getImageResource() {
return new ByteArrayResource("image/jpeg", photo);
}

private IModel<String> getAuthorizedUserLoginNameModel() {
var principal = getMidpointPrincipal();
var loginName = principal == null ? "" : principal.getUsername();
return Model.of(loginName);
private IModel<String> getAuthorizedUserLoginNameModel(UserType user) {
return Model.of(LocalizationUtil.translatePolyString(user.getName()));
}

private void initConfiguredItemsPanel() {
Expand All @@ -176,7 +200,7 @@ protected void populateItem(ListItem<ItemPathType> item) {
}
};
configuredItemsPanel.setOutputMarkupId(true);
configuredItemsPanel.add(new VisibleBehaviour(() -> isUserFound() && configuredItemsExist()));
configuredItemsPanel.add(new VisibleBehaviour(() -> recoveredIdentitiesExist() && configuredItemsExist()));
add(configuredItemsPanel);
}

Expand All @@ -201,7 +225,7 @@ protected IModel<String> getLoginPanelTitleModel() {
}

private String getTitleKey() {
return isUserFound() ? "PageIdentityRecovery.title.success" : "PageIdentityRecovery.title.fail";
return recoveredIdentitiesExist() ? "PageIdentityRecovery.title.success" : "PageIdentityRecovery.title.fail";
}

@Override
Expand All @@ -210,31 +234,57 @@ protected IModel<String> getLoginPanelDescriptionModel() {
}

private String getTitleDescriptionKey() {
if (isUserFound() && configuredItemsExist()) {
if (recoveredIdentitiesExist() && configuredItemsExist()) {
return "PageIdentityRecovery.title.success.configuredItems.description";
}
if (isUserFound()) {
if (recoveredIdentitiesExist()) {
return "PageIdentityRecovery.title.success.description";
}
return "PageIdentityRecovery.title.fail.description";
}

private boolean isUserFound() {
return getMidpointPrincipal() != null;
private boolean recoveredIdentitiesExist() {
return CollectionUtils.isNotEmpty(getRecoveredIdentities());
}

private MidPointPrincipal getMidpointPrincipal() {
var mpAuthentication = getMidpointAuthentication();
var principal = mpAuthentication.getPrincipal();
if (principal instanceof MidPointPrincipal) {
return (MidPointPrincipal) principal;
private boolean isSingleRecoveredIdentity() {
List<UserType> recoveredIdentities = getRecoveredIdentities();
return recoveredIdentities != null && recoveredIdentities.size() == 1;
}

private List<UserType> getRecoveredIdentities() {
var correlationModuleAuth = findCorrelationModuleAuthentication();
if (isSuccessfullyAuthenticated(correlationModuleAuth)) {
return correlationModuleAuth.getOwners()
.stream()
.filter(o -> o instanceof UserType)
.map(o -> (UserType) o)
.collect(Collectors.toList());
}
return Collections.emptyList();
}

private CorrelationModuleAuthentication findCorrelationModuleAuthentication() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (!(authentication instanceof MidpointAuthentication mpAuthentication)) {
getSession().error(getString("No midPoint authentication is found"));
throw new RestartResponseException(PageError.class);
}
return null;
var correlationAuth = (CorrelationModuleAuthentication) mpAuthentication.getAuthentications()
.stream()
.filter(a -> a instanceof CorrelationModuleAuthentication)
.findFirst()
.orElse(null);
return correlationAuth;
}

private boolean isSuccessfullyAuthenticated(CorrelationModuleAuthentication auth) {
return auth != null && AuthenticationModuleState.SUCCESSFULLY.equals(auth.getState());
}

private MidpointAuthentication getMidpointAuthentication() {
var authentication = SecurityContextHolder.getContext().getAuthentication();
if (!(authentication instanceof MidpointAuthentication mpAuthentication)) {
if (!(authentication instanceof MidpointAuthentication)) {
getSession().error(getString("No midPoint authentication is found"));
throw new RestartResponseException(PageError.class);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,14 @@

package com.evolveum.midpoint.authentication.api.config;

import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;

import java.util.List;

public interface CorrelationModuleAuthentication extends ModuleAuthentication {

String getCurrentCorrelatorIdentifier();

List<ObjectType> getOwners();

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,50 @@
*/
package com.evolveum.midpoint.authentication.impl.channel;

import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.repo.api.RepositoryService;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.security.api.AuthorizationConstants;
import com.evolveum.midpoint.task.api.TaskManager;
import com.evolveum.midpoint.util.exception.ObjectNotFoundException;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.xml.ns._public.common.common_3.AuthenticationSequenceChannelType;

import java.util.Collection;
import java.util.Collections;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ServiceType;

public class IdentityRecoveryAuthenticationChannel extends AuthenticationChannelImpl {

public IdentityRecoveryAuthenticationChannel(AuthenticationSequenceChannelType channel) {
private final TaskManager taskManager;
private final RepositoryService repositoryService;

private PrismObject<ServiceType> identityRecoveryService = null;

private static final Trace LOGGER = TraceManager.getTrace(IdentityRecoveryAuthenticationChannel.class);
private static final String DOT_CLASS = IdentityRecoveryAuthenticationChannel.class.getName() + ".";
private static final String IDENTITY_RECOVERY_SERVICE_OID = "00000000-0000-0000-0000-000000000610";
private static final String LOAD_IDENTITY_RECOVERY_SERVICE = DOT_CLASS + "loadIdentityRecoveryService";


public IdentityRecoveryAuthenticationChannel(AuthenticationSequenceChannelType channel, TaskManager taskManager,
RepositoryService repositoryService) {
super(channel);
this.taskManager = taskManager;
this.repositoryService = repositoryService;
loadIdentityRecoveryService();
}

private void loadIdentityRecoveryService() {
var result = taskManager.createTaskInstance(LOAD_IDENTITY_RECOVERY_SERVICE).getResult();
try {
identityRecoveryService = repositoryService.getObject(ServiceType.class, IDENTITY_RECOVERY_SERVICE_OID,
null, result);
} catch (ObjectNotFoundException | SchemaException e) {
LOGGER.debug("Unable to load identity recovery service. ", e);
}
}

public ServiceType getIdentityRecoveryService() {
return identityRecoveryService != null ? identityRecoveryService.asObjectable() : null;
}

public String getChannelId() {
Expand All @@ -27,9 +60,9 @@ public String getPathAfterSuccessfulAuthentication() {
return "/identityRecovery";
}

@Override
protected Collection<String> getAdditionalAuthoritiesList() {
return Collections.singletonList(AuthorizationConstants.AUTZ_UI_IDENTITY_RECOVERY_URL);
}
// @Override
// protected Collection<String> getAdditionalAuthoritiesList() {
// return Collections.singletonList(AuthorizationConstants.AUTZ_UI_IDENTITY_RECOVERY_URL);
// }

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,28 @@

import com.evolveum.midpoint.authentication.api.AuthenticationChannel;
import com.evolveum.midpoint.authentication.impl.channel.IdentityRecoveryAuthenticationChannel;
import com.evolveum.midpoint.repo.api.RepositoryService;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.task.api.TaskManager;
import com.evolveum.midpoint.xml.ns._public.common.common_3.AuthenticationSequenceChannelType;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class IdentityRecoveryChannelFactory extends AbstractChannelFactory {

@Autowired TaskManager taskManager;
@Autowired RepositoryService repositoryService;

@Override
public boolean match(String channelId) {
return SchemaConstants.CHANNEL_IDENTITY_RECOVERY_URI.equals(channelId);
}

@Override
public AuthenticationChannel createAuthChannel(AuthenticationSequenceChannelType channel) {
return new IdentityRecoveryAuthenticationChannel(channel);
return new IdentityRecoveryAuthenticationChannel(channel, taskManager, repositoryService);
}

@Override
Expand Down

0 comments on commit 382145a

Please sign in to comment.