Skip to content

Commit

Permalink
feat(core): remove not allowed roles
Browse files Browse the repository at this point in the history
Depending on where the request comes from, remove roles that are not allowed.

DEPLOYMENT NOTE: New property 'appAllowedRoles' added to the CoreConfig. In perun.properties define 'perun.appAllowedRoles.apps' as a list of names of apps where role limitation is necessary.
For each app name, define regex which maps to the Referer header of the request coming from the given app and a list of allowed roles. For example:
perun.appAllowedRoles.apps=registrar
perun.appAllowedRoles.registrar.reg=^.*/registrar/.*$
perun.appAllowedRoles.registrar.roles=SELF,MFA
  • Loading branch information
sarkapalkovicova committed Aug 2, 2023
1 parent 608fec8 commit c3654b6
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ public void initBeansUtils() {
private int mfaAuthTimeout;
private int mfaAuthTimeoutPercentageForceLogIn;
private boolean enforceMfa;
private Map<String, List<String>> appAllowedRoles = new HashMap<>();
private int idpLoginValidity;
private List<String> idpLoginValidityExceptions;
private int roleUpdateInterval;
Expand Down Expand Up @@ -451,6 +452,35 @@ private String getOidcIssuerProperty(String issuer, String suffix) {
return value;
}

public Map<String, List<String>> getAppAllowedRoles() {
return appAllowedRoles;
}

public void setAppAllowedRoles(List<String> apps) {
for (String app : apps) {
String regex = getAppAllowedRolesProperty(app, "reg");
if (regex == null) continue;

String rolesProperty = getAppAllowedRolesProperty(app, "roles");
if (rolesProperty == null) continue;

List<String> roles = List.of(rolesProperty.split("\s*,\s*"));

log.debug("registering application {} by regex={} with roles={}", app, regex, roles);

this.appAllowedRoles.put(regex, roles);
}
}

private String getAppAllowedRolesProperty(String app, String suffix) {
String property = "perun.appAllowedRoles." + app + "." + suffix;
String value = properties.getProperty(property);
if (value == null) {
log.error("property {} not found, skipping allowed roles for application {}", property, app);
}
return value;
}

public Map<String, String> getOidcIssuersExtsourceNames() {
return oidcIssuersExtsourceNames;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ public class PerunPrincipal {
private User user;
// Contains principal's roles together with objects which specifies the role, e.g. VOADMIN -> list contains VO names
private volatile AuthzRoles authzRoles = new AuthzRoles();
// The PERUNADMIN role is enabled and will not be manually removed
private String referer = "";
// Time of the last update of roles
private long rolesUpdatedAt = System.currentTimeMillis();
// Map contains additional attributes, e.g. from authentication system
Expand Down Expand Up @@ -62,6 +64,12 @@ public PerunPrincipal(String actor, String extSourceName, String extSourceType,
this.additionalInformations = additionalInformations;
}

public PerunPrincipal(String actor, String extSourceName, String extSourceType, int extSourceLoa, Map<String, String> additionalInformations, String referer) {
this(actor, extSourceName, extSourceType, extSourceLoa);
this.additionalInformations = additionalInformations;
this.referer = referer;
}

/**
* Returns actor string representation.
* @return string representing actor
Expand Down Expand Up @@ -153,6 +161,14 @@ public void setRolesUpdatedAt(long rolesUpdatedAt) {
this.rolesUpdatedAt = rolesUpdatedAt;
}

public String getReferer() {
return referer;
}

public void setReferer(String referer) {
this.referer = referer;
}

@Override
public int hashCode() {
final int prime = 31;
Expand Down
3 changes: 3 additions & 0 deletions perun-base/src/main/resources/perun-base.xml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
<property name="mfaAuthTimeout" value="${perun.introspectionEndpoint.mfaAuthTimeout}"/>
<property name="mfaAuthTimeoutPercentageForceLogIn" value="${perun.introspectionEndpoint.mfaAuthTimeoutPercentageForceLogIn}"/>
<property name="enforceMfa" value="${perun.enforceMfa}"/>
<property name="appAllowedRoles" value="#{'${perun.appAllowedRoles.apps}'.split('\s*,\s*')}"/>
<property name="introspectionEndpointMfaAcrValue" value="${perun.introspectionEndpoint.mfaAcrValue}"/>
<property name="idpLoginValidity" value="${perun.idpLoginValidity}"/>
<property name="idpLoginValidityExceptions" value="#{'${perun.idpLoginValidityExceptions}'.split('\s*,\s*')}"/>
Expand Down Expand Up @@ -169,6 +170,8 @@
<prop key="perun.oidc.i2.extsource.name">https://login.elixir-czech.org/idp/</prop>
<prop key="perun.oidc.i2.extsource.type">cz.metacentrum.perun.core.impl.ExtSourceIdp</prop>

<prop key="perun.appAllowedRoles.apps"></prop>

<prop key="notif.sendMessages">true</prop>
<prop key="mail.smtp.host">localhost</prop>
<prop key="mail.smtp.from"></prop>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
import java.util.concurrent.TimeUnit;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static cz.metacentrum.perun.core.api.AuthzResolver.MFA_CRITICAL_ATTR;
Expand Down Expand Up @@ -2572,6 +2573,19 @@ public static synchronized void refreshAuthz(PerunSession sess) {
setAdditionalRoles(sess, roles, user);
}

// Remove roles which are not allowed
Map<String, List<String>> appAllowedRoles = BeansUtils.getCoreConfig().getAppAllowedRoles();
for (String reg : appAllowedRoles.keySet()) {
Pattern pattern = Pattern.compile(reg);
if (pattern.matcher(sess.getPerunPrincipal().getReferer()).matches()) {
for (String role : roles.getRolesNames()) {
if (!appAllowedRoles.get(reg).contains(role)) {
roles.remove(role);
}
}
}
}

sess.getPerunPrincipal().setRoles(roles);

if (sess.getPerunClient().getType() == PerunClient.Type.OAUTH) {
Expand Down
6 changes: 4 additions & 2 deletions perun-rpc/src/main/java/cz/metacentrum/perun/rpc/Api.java
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,8 @@ private static PerunPrincipal setupPerunPrincipal(HttpServletRequest req, Deseri
int extSourceLoa;
Map<String, String> additionalInformations = new HashMap<>();

String referer = req.getHeader("Referer");

String shibIdentityProvider = getStringAttribute(req, SHIB_IDENTITY_PROVIDER);
String sourceIdpEntityId = getStringAttribute(req, SOURCE_IDP_ENTITY_ID);
String remoteUser = req.getRemoteUser();
Expand Down Expand Up @@ -415,8 +417,8 @@ else if (Objects.equals(req.getAttribute(SSL_CLIENT_VERIFY), SUCCESS)) {
if (isEmpty(extLogin) || isEmpty(extSourceName)) {
throw new UserNotExistsException("extLogin or extSourceName is empty");
}
log.trace("creating PerunPrincipal(actor={},extSourceName={},extSourceType={},extSourceLoa={},additionalInformations={})",extLogin,extSourceName, extSourceType, extSourceLoa, additionalInformations);
return new PerunPrincipal(extLogin, extSourceName, extSourceType, extSourceLoa, additionalInformations);
log.trace("creating PerunPrincipal(actor={},extSourceName={},extSourceType={},extSourceLoa={},additionalInformations={},referer={})",extLogin,extSourceName, extSourceType, extSourceLoa, additionalInformations, referer);
return new PerunPrincipal(extLogin, extSourceName, extSourceType, extSourceLoa, additionalInformations, referer);
}

private PerunClient setupPerunClient(HttpServletRequest req) {
Expand Down

0 comments on commit c3654b6

Please sign in to comment.