Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
tonydamage committed Feb 21, 2024
2 parents 123da15 + a0a41d1 commit 6df85b2
Show file tree
Hide file tree
Showing 33 changed files with 432 additions and 68 deletions.
4 changes: 0 additions & 4 deletions gui/admin-gui/src/frontend/scss/_admin-lte-overrides.scss
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,6 @@
margin-right: -0.625rem;
}

.role-catalog-tiles-table div.img-circle {
background-color: #f5f5f5;
}

.dropdown-toggle:after {
vertical-align: middle;
/*margin: 0 0.255em;*/
Expand Down
4 changes: 4 additions & 0 deletions gui/admin-gui/src/frontend/scss/_tables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,7 @@ th.countLabel{
// See com.evolveum.midpoint.web.page.admin.certification.PageCertDecisions
width: 70px;
}

td.rounded-icon-column div.img-circle {
background-color: #f5f5f5;
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import java.util.List;
import javax.xml.datatype.XMLGregorianCalendar;

import com.evolveum.midpoint.gui.impl.util.IconAndStylesUtil;
import com.evolveum.midpoint.gui.impl.util.RelationUtil;

import org.apache.commons.lang3.BooleanUtils;
Expand Down Expand Up @@ -418,11 +419,28 @@ protected IResource load() {
}
};
}

@Override
protected DisplayType createDisplayType(IModel<ShoppingCartItem> model) {
AssignmentType a = model.getObject().getAssignment();
ObjectReferenceType ref = a != null ? a.getTargetRef() : null;

if (ref == null || ref.getType() == null) {
return null;
}

String icon = IconAndStylesUtil.createDefaultBlackIcon(ref.getType());

return new DisplayType()
.icon(new IconType()
.cssClass(icon));
}
});
columns.add(new AbstractColumn<>(createStringResource("ShoppingCartPanel.accessName")) {

@Override
public void populateItem(Item<ICellPopulator<ShoppingCartItem>> item, String id, IModel<ShoppingCartItem> model) {
item.add(AttributeAppender.append("class", "align-middle"));
item.add(new Label(id, () -> {
ShoppingCartItem cartItem = model.getObject();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,9 @@ protected DisplayType createDisplayType(IModel<T> model) {
protected IModel<IResource> createPreferredImage(IModel<T> model) {
return () -> null;
}

@Override
public String getCssClass() {
return "rounded-icon-column";
}
}
8 changes: 8 additions & 0 deletions model/authentication-impl/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<!-- Spring Security CAS was removed in spring 6.0.x -->
<!--
<dependency>
Expand Down Expand Up @@ -126,6 +130,10 @@
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@
*/
package com.evolveum.midpoint.authentication.impl.authorization.evaluator;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.*;

import com.evolveum.midpoint.authentication.impl.authorization.AuthorizationActionValue;
import com.evolveum.midpoint.authentication.impl.authorization.DescriptorLoaderImpl;
Expand All @@ -18,10 +15,14 @@

import com.evolveum.midpoint.prism.*;
import com.evolveum.midpoint.security.api.*;

import jakarta.servlet.http.HttpServletRequest;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
Expand All @@ -47,6 +48,10 @@
import com.evolveum.midpoint.authentication.impl.module.configuration.ModuleWebSecurityConfigurationImpl;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;

import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.HandlerMapping;

public class MidPointGuiAuthorizationEvaluator implements SecurityEnforcer, SecurityContextManager, AccessDecisionManager {

private static final Trace LOGGER = TraceManager.getTrace(MidPointGuiAuthorizationEvaluator.class);
Expand All @@ -56,12 +61,20 @@ public class MidPointGuiAuthorizationEvaluator implements SecurityEnforcer, Secu
private final SecurityEnforcer securityEnforcer;
private final SecurityContextManager securityContextManager;
private final TaskManager taskManager;
private final ApplicationContext applicationContext;

/** Used to retrieve REST handler methods' information. Lazily evaluated. */
private List<HandlerMapping> handlerMappingBeans = List.of();

public MidPointGuiAuthorizationEvaluator(SecurityEnforcer securityEnforcer, SecurityContextManager securityContextManager, TaskManager taskManager) {
super();
public MidPointGuiAuthorizationEvaluator(
SecurityEnforcer securityEnforcer,
SecurityContextManager securityContextManager,
TaskManager taskManager,
ApplicationContext applicationContext) {
this.securityEnforcer = securityEnforcer;
this.securityContextManager = securityContextManager;
this.taskManager = taskManager;
this.applicationContext = applicationContext;
}

@Override
Expand Down Expand Up @@ -193,7 +206,7 @@ public void decide(Authentication authentication, Object object, Collection<Conf
return;
}

List<String> requiredActions = new ArrayList<>();
Set<String> requiredActions = new HashSet<>();

for (EndPointsUrlMapping urlMapping : EndPointsUrlMapping.values()) {
addSecurityConfig(filterInvocation, requiredActions, urlMapping.getUrl(), urlMapping.getAction());
Expand All @@ -204,6 +217,11 @@ public void decide(Authentication authentication, Object object, Collection<Conf
addSecurityConfig(filterInvocation, requiredActions, entry.getKey(), entry.getValue());
}

HandlerMethod restHandlerMethod = getRestHandlerMethod(filterInvocation.getRequest());
if (restHandlerMethod != null) {
addSecurityConfig(requiredActions, restHandlerMethod);
}

if (requiredActions.isEmpty()) {
LOGGER.trace("DECIDE: DENY because determined empty required actions from {}", filterInvocation);
SecurityUtil.logSecurityDeny(object, ": Not authorized (page without authorizations)", null, requiredActions);
Expand All @@ -219,6 +237,26 @@ public void decide(Authentication authentication, Object object, Collection<Conf
decideInternal(principal, requiredActions, authentication, object, task);
}

private HandlerMethod getRestHandlerMethod(HttpServletRequest request) {
if (handlerMappingBeans.isEmpty()) {
handlerMappingBeans = new ArrayList<>(
BeanFactoryUtils.beansOfTypeIncludingAncestors(
applicationContext, HandlerMapping.class, true, false).values());
}

for (HandlerMapping handlerMapping : handlerMappingBeans) {
try {
HandlerExecutionChain handler = handlerMapping.getHandler(request);
if (handler != null && handler.getHandler() instanceof HandlerMethod method) {
return method;
}
} catch (Exception e) {
// ignore exception
}
}
return null;
}

protected MidPointPrincipal getPrincipalFromAuthentication(
Authentication authentication, Object object, Object configAttributes) {
Object principalObject = authentication.getPrincipal();
Expand All @@ -238,7 +276,8 @@ protected MidPointPrincipal getPrincipalFromAuthentication(
MidPointPrincipal.class.getName() + " but it was " + (principalObject == null ? null : principalObject.getClass()));
}

protected void decideInternal(MidPointPrincipal principal, List<String> requiredActions, Authentication authentication, Object object, Task task) {
protected void decideInternal(
MidPointPrincipal principal, Set<String> requiredActions, Authentication authentication, Object object, Task task) {

AccessDecision decision;
try {
Expand Down Expand Up @@ -287,8 +326,8 @@ && new AntPathRequestMatcher(AUTH_URL).matches(filterInvocation.getRequest())) {
return false;
}

private void addSecurityConfig(FilterInvocation filterInvocation, List<String> requiredActions,
String url, DisplayableValue<String>[] actions) {
private void addSecurityConfig(
FilterInvocation filterInvocation, Set<String> requiredActions, String url, DisplayableValue<String>[] actions) {

AntPathRequestMatcher matcher = new AntPathRequestMatcher(url);
if (!matcher.matches(filterInvocation.getRequest()) || actions == null) {
Expand All @@ -297,16 +336,22 @@ private void addSecurityConfig(FilterInvocation filterInvocation, List<String> r

for (DisplayableValue<String> action : actions) {
String actionUri = action.getValue();
if (StringUtils.isBlank(actionUri)) {
continue;
}

if (!requiredActions.contains(actionUri)) {
if (!StringUtils.isBlank(actionUri)) {
requiredActions.add(actionUri);
}
}
}

/** Adds a required action specific to given REST handler method. */
private void addSecurityConfig(Set<String> requiredActions, HandlerMethod restHandlerMethod) {
var annotation = restHandlerMethod.getMethodAnnotation(RestHandlerMethod.class);
if (annotation != null) {
requiredActions.add(annotation.authorization().getUri());
} else {
// No additional info. We do the authorization in a traditional way (`rest-3#all` or cluster authentication).
}
}

@Override
public @NotNull <O extends ObjectType> ObjectSecurityConstraints compileSecurityConstraints(
@NotNull PrismObject<O> object, boolean fullInformationAvailable, @NotNull Options options,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import java.util.Collection;

import org.springframework.context.ApplicationContext;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.InsufficientAuthenticationException;
Expand All @@ -23,8 +24,8 @@
public class MidpointAllowAllAuthorizationEvaluator extends MidPointGuiAuthorizationEvaluator {

public MidpointAllowAllAuthorizationEvaluator(
SecurityEnforcer securityEnforcer, SecurityContextManager securityContextManager, TaskManager taskManager) {
super(securityEnforcer, securityContextManager, taskManager);
SecurityEnforcer securityEnforcer, SecurityContextManager securityContextManager, TaskManager taskManager, ApplicationContext applicationContext) {
super(securityEnforcer, securityContextManager, taskManager, applicationContext);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import com.evolveum.midpoint.authentication.api.config.MidpointAuthentication;
import com.evolveum.midpoint.authentication.api.config.ModuleAuthentication;

import org.springframework.context.ApplicationContext;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.InsufficientAuthenticationException;
Expand Down Expand Up @@ -54,8 +55,8 @@ public class MidpointHttpAuthorizationEvaluator extends MidPointGuiAuthorization
private final SecurityContextManager securityContextManager;

public MidpointHttpAuthorizationEvaluator(SecurityEnforcer securityEnforcer, SecurityContextManager securityContextManager,
TaskManager taskManager, ModelService model) {
super(securityEnforcer, securityContextManager, taskManager);
TaskManager taskManager, ModelService model, ApplicationContext applicationContext) {
super(securityEnforcer, securityContextManager, taskManager, applicationContext);
this.model = model;
this.taskManager = taskManager;
this.securityContextManager = securityContextManager;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ public class SecurityConfigurer {
@Autowired
private ApplicationContext context;

@Autowired
private ApplicationContext applicationContext;

private ObjectPostProcessor<Object> objectObjectPostProcessor;
private ContentNegotiationStrategy contentNegotiationStrategy = new HeaderContentNegotiationStrategy();

Expand All @@ -99,7 +102,7 @@ public void setObjectPostProcessor(ObjectPostProcessor<Object> objectPostProcess
public MidPointGuiAuthorizationEvaluator accessDecisionManager(SecurityEnforcer securityEnforcer,
SecurityContextManager securityContextManager,
TaskManager taskManager) {
return new MidPointGuiAuthorizationEvaluator(securityEnforcer, securityContextManager, taskManager);
return new MidPointGuiAuthorizationEvaluator(securityEnforcer, securityContextManager, taskManager, applicationContext);
}

@Bean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import jakarta.servlet.ServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
Expand All @@ -43,6 +44,7 @@ public class HttpBasicModuleWebSecurityConfigurer extends ModuleWebSecurityConfi
@Autowired private SecurityEnforcer securityEnforcer;
@Autowired private SecurityContextManager securityContextManager;
@Autowired private TaskManager taskManager;
@Autowired private ApplicationContext applicationContext;

public HttpBasicModuleWebSecurityConfigurer(HttpBasicAuthenticationModuleType module,
String sequenceSuffix,
Expand Down Expand Up @@ -73,7 +75,8 @@ protected void configure(HttpSecurity http) throws Exception {
if (rememberMeServices != null) {
filter.setRememberMeServices(rememberMeServices);
}
http.authorizeRequests().accessDecisionManager(new MidpointHttpAuthorizationEvaluator(securityEnforcer, securityContextManager, taskManager, model));
http.authorizeRequests().accessDecisionManager(new MidpointHttpAuthorizationEvaluator(
securityEnforcer, securityContextManager, taskManager, model, applicationContext));
http.addFilterAt(filter, BasicAuthenticationFilter.class);

http.formLogin().disable()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import jakarta.servlet.ServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
Expand All @@ -38,6 +39,7 @@ public class HttpClusterModuleWebSecurityConfigurer extends ModuleWebSecurityCon
@Autowired private SecurityEnforcer securityEnforcer;
@Autowired private SecurityContextManager securityContextManager;
@Autowired private TaskManager taskManager;
@Autowired private ApplicationContext applicationContext;

public HttpClusterModuleWebSecurityConfigurer(AbstractAuthenticationModuleType moduleType,
String sequeneSuffix,
Expand Down Expand Up @@ -67,7 +69,8 @@ protected void configure(HttpSecurity http) throws Exception {
if (rememberMeServices != null) {
filter.setRememberMeServices(rememberMeServices);
}
http.authorizeRequests().accessDecisionManager(new MidpointAllowAllAuthorizationEvaluator(securityEnforcer, securityContextManager, taskManager));
http.authorizeRequests().accessDecisionManager(new MidpointAllowAllAuthorizationEvaluator(
securityEnforcer, securityContextManager, taskManager, applicationContext));
http.addFilterAt(filter, BasicAuthenticationFilter.class);
http.formLogin().disable()
.csrf().disable();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import jakarta.servlet.ServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
Expand Down Expand Up @@ -51,6 +52,9 @@ public class HttpSecurityQuestionsModuleWebSecurityConfigurer extends ModuleWebS
@Autowired
private TaskManager taskManager;

@Autowired
private ApplicationContext applicationContext;

public HttpSecurityQuestionsModuleWebSecurityConfigurer(HttpSecQAuthenticationModuleType moduleType,
String suffix,
AuthenticationChannel authenticationChannel,
Expand All @@ -74,7 +78,8 @@ protected void configure(HttpSecurity http) throws Exception {
HttpAuthenticationEntryPoint entryPoint = getObjectPostProcessor().postProcess(new HttpSecurityQuestionsAuthenticationEntryPoint());
http.securityMatcher(AuthUtil.stripEndingSlashes(getPrefix()) + "/**");

http.authorizeRequests().accessDecisionManager(new MidpointHttpAuthorizationEvaluator(securityEnforcer, securityContextManager, taskManager, model));
http.authorizeRequests().accessDecisionManager(new MidpointHttpAuthorizationEvaluator(
securityEnforcer, securityContextManager, taskManager, model, applicationContext));

HttpSecurityQuestionsAuthenticationFilter filter = getObjectPostProcessor().postProcess(new HttpSecurityQuestionsAuthenticationFilter(authenticationManager(), entryPoint));
RememberMeServices rememberMeServices = http.getSharedObject(RememberMeServices.class);
Expand Down

0 comments on commit 6df85b2

Please sign in to comment.