refactor: Refactoring AuthProcFilters

pull/1580/head
Dominik František Bučík 2022-05-31 16:13:09 +02:00
parent 64a22d758f
commit 677943d4d6
No known key found for this signature in database
GPG Key ID: 73F752BEC0709845
32 changed files with 661 additions and 860 deletions

View File

@ -252,7 +252,7 @@
<security:intercept-url pattern="#{T(cz.muni.ics.oidc.web.controllers.LoginController).MAPPING_FAILURE}" <security:intercept-url pattern="#{T(cz.muni.ics.oidc.web.controllers.LoginController).MAPPING_FAILURE}"
access="permitAll()"/> access="permitAll()"/>
<security:intercept-url pattern="/**" access="hasRole('ROLE_USER')"/> <security:intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>
<security:custom-filter ref="mdcMuFilter" before="FIRST"/> <security:custom-filter ref="mdcFilter" before="FIRST"/>
<security:custom-filter ref="metadataGeneratorFilter" before="CHANNEL_FILTER"/> <security:custom-filter ref="metadataGeneratorFilter" before="CHANNEL_FILTER"/>
<security:custom-filter ref="clearSessionFilter" after="CHANNEL_FILTER"/> <security:custom-filter ref="clearSessionFilter" after="CHANNEL_FILTER"/>
<security:custom-filter ref="samlFilter" before="CSRF_FILTER"/> <security:custom-filter ref="samlFilter" before="CSRF_FILTER"/>
@ -337,8 +337,6 @@
<property name="order" value="1" /> <property name="order" value="1" />
</bean> </bean>
<bean id="mdcMuFilter" class="cz.muni.ics.oidc.server.filters.impl.MultiMDCFilter"/>
<!-- SAML --> <!-- SAML -->
<bean id="clearSessionFilter" class="cz.muni.ics.oidc.saml.SamlInvalidateSessionFilter"> <bean id="clearSessionFilter" class="cz.muni.ics.oidc.saml.SamlInvalidateSessionFilter">
<constructor-arg name="contextLogoutHandler" ref="logoutHandler"/> <constructor-arg name="contextLogoutHandler" ref="logoutHandler"/>
@ -362,7 +360,7 @@
<bean id="successLogoutHandler" class="cz.muni.ics.oidc.saml.PerunOidcLogoutSuccessHandler"> <bean id="successLogoutHandler" class="cz.muni.ics.oidc.saml.PerunOidcLogoutSuccessHandler">
<property name="defaultTargetUrl" value="#{T(cz.muni.ics.oidc.web.controllers.LogoutController).MAPPING_SUCCESS}"/> <property name="defaultTargetUrl" value="#{T(cz.muni.ics.oidc.web.controllers.LogoutController).MAPPING_SUCCESS}"/>
<property name="targetUrlParameter" value="#{T(cz.muni.ics.oidc.server.filters.PerunFilterConstants).PARAM_TARGET}"/> <property name="targetUrlParameter" value="#{T(cz.muni.ics.oidc.server.filters.AuthProcFilterConstants).PARAM_TARGET}"/>
</bean> </bean>
<bean id="logoutHandler" class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"> <bean id="logoutHandler" class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler">

View File

@ -20,10 +20,10 @@ public class RemoteAddressMDCFilter {
"REMOTE_ADDR" "REMOTE_ADDR"
}; };
private static final String REMOTE_ADDR = "remoteAddr"; private static final String REMOTE_ADDRESS = "remoteAddr";
public void doFilter(ServletRequest servletRequest) { public void doFilter(ServletRequest servletRequest) {
MDC.put(REMOTE_ADDR, getRemoteAddr((HttpServletRequest) servletRequest)); MDC.put(REMOTE_ADDRESS, getRemoteAddr((HttpServletRequest) servletRequest));
} }
private String getRemoteAddr(HttpServletRequest request) { private String getRemoteAddr(HttpServletRequest request) {
@ -37,7 +37,7 @@ public class RemoteAddressMDCFilter {
return ipList.split(",")[0]; return ipList.split(",")[0];
} }
} }
return ""; return "-";
} }
} }

View File

@ -0,0 +1,11 @@
package cz.muni.ics.oidc;
public interface PerunConstants {
String REGISTRAR_TARGET_NEW = "targetnew";
String REGISTRAR_TARGET_EXISTING = "targetexisting";
String REGISTRAR_TARGET_EXTENDED = "targetextended";
String REGISTRAR_PARAM_VO = "vo";
}

View File

@ -7,7 +7,7 @@ import org.opensaml.ws.message.encoder.MessageEncodingException;
import org.opensaml.xml.util.Pair; import org.opensaml.xml.util.Pair;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.AARC_IDP_HINT; import static cz.muni.ics.oidc.server.filters.AuthProcFilterConstants.AARC_IDP_HINT;
public class PerunHTTPRedirectDeflateEncoder extends HTTPRedirectDeflateEncoder { public class PerunHTTPRedirectDeflateEncoder extends HTTPRedirectDeflateEncoder {

View File

@ -1,7 +1,7 @@
package cz.muni.ics.oidc.saml; package cz.muni.ics.oidc.saml;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_POST_LOGOUT_REDIRECT_URI; import static cz.muni.ics.oidc.server.filters.AuthProcFilterConstants.PARAM_POST_LOGOUT_REDIRECT_URI;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_STATE; import static cz.muni.ics.oidc.server.filters.AuthProcFilterConstants.PARAM_STATE;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.URLDecoder; import java.net.URLDecoder;

View File

@ -1,20 +1,20 @@
package cz.muni.ics.oidc.saml; package cz.muni.ics.oidc.saml;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.AARC_IDP_HINT; import static cz.muni.ics.oidc.server.filters.AuthProcFilterConstants.AARC_IDP_HINT;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.CLIENT_ID_PREFIX; import static cz.muni.ics.oidc.server.filters.AuthProcFilterConstants.CLIENT_ID_PREFIX;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.EFILTER_PREFIX; import static cz.muni.ics.oidc.server.filters.AuthProcFilterConstants.EFILTER_PREFIX;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.FILTER_PREFIX; import static cz.muni.ics.oidc.server.filters.AuthProcFilterConstants.FILTER_PREFIX;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.IDP_ENTITY_ID_PREFIX; import static cz.muni.ics.oidc.server.filters.AuthProcFilterConstants.IDP_ENTITY_ID_PREFIX;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_CLIENT_ID; import static cz.muni.ics.oidc.server.filters.AuthProcFilterConstants.PARAM_CLIENT_ID;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_PROMPT; import static cz.muni.ics.oidc.server.filters.AuthProcFilterConstants.PARAM_PROMPT;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.REFEDS_MFA; import static cz.muni.ics.oidc.server.filters.AuthProcFilterConstants.REFEDS_MFA;
import cz.muni.ics.oidc.models.Facility; import cz.muni.ics.oidc.models.Facility;
import cz.muni.ics.oidc.models.PerunAttributeValue; import cz.muni.ics.oidc.models.PerunAttributeValue;
import cz.muni.ics.oidc.server.adapters.PerunAdapter; import cz.muni.ics.oidc.server.adapters.PerunAdapter;
import cz.muni.ics.oidc.server.configurations.FacilityAttrsConfig; import cz.muni.ics.oidc.server.configurations.FacilityAttrsConfig;
import cz.muni.ics.oidc.server.configurations.PerunOidcConfig; import cz.muni.ics.oidc.server.configurations.PerunOidcConfig;
import cz.muni.ics.oidc.server.filters.PerunFilterConstants; import cz.muni.ics.oidc.server.filters.AuthProcFilterConstants;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -160,12 +160,12 @@ public class PerunSamlEntryPoint extends SAMLEntryPoint {
} }
private void processAcrValues(HttpServletRequest request, WebSSOProfileOptions options) { private void processAcrValues(HttpServletRequest request, WebSSOProfileOptions options) {
String acrValues = request.getParameter(PerunFilterConstants.PARAM_ACR_VALUES); String acrValues = request.getParameter(AuthProcFilterConstants.PARAM_ACR_VALUES);
log.debug("Processing acr_values parameter: {}", acrValues); log.debug("Processing acr_values parameter: {}", acrValues);
List<String> acrs = convertAcrValuesToList(acrValues); List<String> acrs = convertAcrValuesToList(acrValues);
if (!hasAcrForcingIdp(acrs)) { if (!hasAcrForcingIdp(acrs)) {
String clientId = request.getParameter(PerunFilterConstants.PARAM_CLIENT_ID); String clientId = request.getParameter(AuthProcFilterConstants.PARAM_CLIENT_ID);
String idpFilter = extractIdpFilterForRp(clientId); String idpFilter = extractIdpFilterForRp(clientId);
if (idpFilter != null) { if (idpFilter != null) {
log.debug("Added IdP filter as SAML AuthnContextClassRef ({})", idpFilter); log.debug("Added IdP filter as SAML AuthnContextClassRef ({})", idpFilter);

View File

@ -1,12 +1,12 @@
package cz.muni.ics.oidc.saml; package cz.muni.ics.oidc.saml;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_ACR_VALUES; import static cz.muni.ics.oidc.server.filters.AuthProcFilterConstants.PARAM_ACR_VALUES;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_FORCE_AUTHN; import static cz.muni.ics.oidc.server.filters.AuthProcFilterConstants.PARAM_FORCE_AUTHN;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_PROMPT; import static cz.muni.ics.oidc.server.filters.AuthProcFilterConstants.PARAM_PROMPT;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PROMPT_LOGIN; import static cz.muni.ics.oidc.server.filters.AuthProcFilterConstants.PROMPT_LOGIN;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PROMPT_SELECT_ACCOUNT; import static cz.muni.ics.oidc.server.filters.AuthProcFilterConstants.PROMPT_SELECT_ACCOUNT;
import cz.muni.ics.oidc.server.filters.PerunFilterConstants; import cz.muni.ics.oidc.server.filters.AuthProcFilterConstants;
import javax.servlet.ServletRequest; import javax.servlet.ServletRequest;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@ -32,7 +32,7 @@ public class PerunSamlUtils {
public static boolean needsReAuthByMfa(ServletRequest request) { public static boolean needsReAuthByMfa(ServletRequest request) {
String acrValues = request.getParameter(PARAM_ACR_VALUES); String acrValues = request.getParameter(PARAM_ACR_VALUES);
boolean res = StringUtils.hasText(acrValues) boolean res = StringUtils.hasText(acrValues)
&& acrValues.contains(PerunFilterConstants.REFEDS_MFA); && acrValues.contains(AuthProcFilterConstants.REFEDS_MFA);
log.debug("requires reAuth by MFA acr - {}", res); log.debug("requires reAuth by MFA acr - {}", res);
return res; return res;
} }

View File

@ -1,31 +1,37 @@
package cz.muni.ics.oidc.server.filters; package cz.muni.ics.oidc.server.filters;
import cz.muni.ics.oidc.exceptions.ConfigurationException;
import cz.muni.ics.oidc.saml.SamlProperties;
import java.io.IOException; import java.io.IOException;
import java.security.Principal;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSession;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
/** /**
* Abstract class for Perun filters. All filters called in CallPerunFiltersFilter has to extend this. * Abstract class for Perun AuthProc filters. All filters defined and called in the
* * {@link cz.muni.ics.oidc.server.filters.AuthProcFiltersContainer} instance have to extend this base class.
* Configuration of filter names:
* <ul>
* <li><b>filter.names</b> - comma separated list of names of the request filters</li>
* </ul>
* *
* Configuration of filter (replace [name] part with the name defined for the filter): * Configuration of filter (replace [name] part with the name defined for the filter):
* <ul> * <ul>
* <li><b>filter.[name].class</b> - Class the filter instantiates</li> * <li><b>filter.[name].class</b> - Class the filter instantiates</li>
* <li><b>filter.[name].subs</b> - comma separated list of sub values for which execution of filter will be skipped * <li><b>filter.[name].skip_for_users</b> - comma separated list of users for whom the execution of the filter
* if user's SUB is in the list</li> * will be skipped if the users' SUB matches any value in the list</li>
* <li><b>filter.[name].clientIds</b> - comma separated list of client_id values for which execution of filter * <li><b>filter.[name].skip_for_clients</b> - comma separated list of clients for which the execution of the filter
* will be skipped if client_id is in the list</li> * will be skipped if the CLIENT_ID matches any value in the list</li>
* <li><b>filter.[name].execute_for_users</b> - comma separated list of users for whom the filter will be executed
* if the users' SUB matches any value in the list</li>
* <li><b>filter.[name].execute_for_clients</b> - comma separated list of clients for whom the filter will be executed
* if the CLIENT_ID matches any value in the list</li>
* </ul> * </ul>
* <i>NOTE: if none of the SKIP/EXECUTE conditions is specified (or the lists are empty), filter is run for all users
* and all clients</i>
* *
* @see cz.muni.ics.oidc.server.filters.impl package for specific filters and their configuration * @see cz.muni.ics.oidc.server.filters.impl package for specific filters and their configuration
* *
@ -33,33 +39,57 @@ import lombok.extern.slf4j.Slf4j;
* @author Dominik Frantisek Bucik <bucik@ics.muni.cz> * @author Dominik Frantisek Bucik <bucik@ics.muni.cz>
*/ */
@Slf4j @Slf4j
@Getter
public abstract class AuthProcFilter { public abstract class AuthProcFilter {
public static final String APPLIED = "APPLIED_";
private static final String DELIMITER = ","; private static final String DELIMITER = ",";
private static final String CLIENT_IDS = "clientIds"; private static final String EXECUTE = "execute";
private static final String EXECUTE_FOR_CLIENTS = "execute_for_clients";
private static final String EXECUTE_FOR_USERS = "execute_for_users";
private static final String SKIP_FOR_CLIENTS = "skip_for_clients";
private static final String SKIP_FOR_USERS = "skip_for_users";
private static final String SUBS = "subs"; private static final String SUBS = "subs";
private static final String CLIENT_IDS = "clientIds";
private final String filterName; private final String filterName;
private Set<String> clientIds = new HashSet<>(); private final Set<String> executeForClients = new HashSet<>();
private Set<String> subs = new HashSet<>(); private final Set<String> executeForUsers = new HashSet<>();
private final Set<String> skipForClients = new HashSet<>();
private final Set<String> skipForUsers = new HashSet<>();
public AuthProcFilter(AuthProcFilterParams params) { private final SamlProperties samlProperties;
filterName = params.getFilterName();
if (params.hasProperty(CLIENT_IDS)) { public AuthProcFilter(AuthProcFilterInitContext ctx) throws ConfigurationException {
this.clientIds = new HashSet<>(Arrays.asList(params.getProperty(CLIENT_IDS).split(DELIMITER))); filterName = ctx.getFilterName();
this.samlProperties = ctx.getBeanUtil().getBean(SamlProperties.class);
initializeExecutionRulesLists(ctx);
if (!Collections.disjoint(executeForClients, skipForClients)) {
throw new ConfigurationException("Filter '" + filterName + "' is configured to be run and skipped for the same client");
} else if (!Collections.disjoint(executeForUsers, skipForUsers)) {
throw new ConfigurationException("Filter '" + filterName + "' is configured to be run and skipped for the same user");
} }
if (params.hasProperty(SUBS)) { log.info("{} - filter initialized", filterName);
this.subs = new HashSet<>(Arrays.asList(params.getProperty(SUBS).split(DELIMITER))); if (!skipForUsers.isEmpty()) {
log.info("{} - skip execution for users with SUB in: '{}'", filterName, skipForUsers);
}
if (!skipForClients.isEmpty()) {
log.info("{} - skip execution for clients with CLIENT_ID in: '{}'", filterName, skipForClients);
}
if (!executeForUsers.isEmpty()) {
log.info("{} - execute for users with SUB in: '{}'", filterName, executeForUsers);
}
if (!executeForClients.isEmpty()) {
log.info("{} - execute for clients with CLIENT_ID in: '{}'", filterName, executeForClients);
} }
log.debug("{} - filter initialized", filterName);
log.debug("{} - skip execution for users with SUB in: {}", filterName, subs);
log.debug("{} - skip execution for clients with CLIENT_ID in: {}", filterName, clientIds);
} }
protected abstract String getSessionAppliedParamName(); protected String getSessionAppliedParamName() {
return APPLIED + getClass().getSimpleName() + '_' + getFilterName();
}
/** /**
* In this method is done whole logic of filer * In this method is done whole logic of filer
@ -69,10 +99,10 @@ public abstract class AuthProcFilter {
* @return boolean if filter was successfully done * @return boolean if filter was successfully done
* @throws IOException this exception could be thrown because of failed or interrupted I/O operation * @throws IOException this exception could be thrown because of failed or interrupted I/O operation
*/ */
protected abstract boolean process(HttpServletRequest request, HttpServletResponse response, FilterParams params) protected abstract boolean process(HttpServletRequest request, HttpServletResponse response, AuthProcFilterCommonVars params)
throws IOException; throws IOException;
public boolean doFilter(HttpServletRequest req, HttpServletResponse res, FilterParams params) throws IOException { public boolean doFilter(HttpServletRequest req, HttpServletResponse res, AuthProcFilterCommonVars params) throws IOException {
if (!skip(req)) { if (!skip(req)) {
log.trace("{} - executing filter", filterName); log.trace("{} - executing filter", filterName);
return process(req, res, params); return process(req, res, params);
@ -81,14 +111,18 @@ public abstract class AuthProcFilter {
} }
} }
private boolean skip(HttpServletRequest request) { private boolean skip(HttpServletRequest req) {
if (hasBeenApplied(request.getSession(true))) { if (hasBeenApplied(req.getSession(true))) {
return true; return true;
} }
log.debug("{} - marking filter as applied", filterName); log.debug("{} - marking filter as applied", filterName);
request.getSession(true).setAttribute(getSessionAppliedParamName(), true); req.getSession(true).setAttribute(getSessionAppliedParamName(), true);
return skipForSub(request.getUserPrincipal()) String sub = FiltersUtils.getUserIdentifier(req, samlProperties.getUserIdentifierAttribute());
|| skipForClientId(request.getParameter(PerunFilterConstants.PARAM_CLIENT_ID)); String clientId = FiltersUtils.getClientId(req);
boolean explicitExecution = executeForSub(sub) || executeForClientId(clientId);
boolean explicitSkip = skipForClientId(clientId) || skipForSub(sub);
return !explicitExecution && explicitSkip;
} }
private boolean hasBeenApplied(HttpSession sess) { private boolean hasBeenApplied(HttpSession sess) {
@ -100,21 +134,45 @@ public abstract class AuthProcFilter {
return false; return false;
} }
private boolean skipForSub(Principal p) { private boolean executeForSub(String sub) {
String sub = (p != null) ? p.getName() : null; return checkRule(sub, executeForUsers, "{} - execute filter: matched one of the explicit SUBS ({})");
if (sub != null && subs.contains(sub)) { }
log.debug("{} - skip filter execution: matched one of the ignored SUBS ({})", filterName, sub);
return true; private boolean executeForClientId(String clientId) {
} return checkRule(clientId, executeForClients, "{} - execute filter: matched one of the explicit CLIENT_IDS ({})");
return false; }
private boolean skipForSub(String sub) {
return checkRule(sub, skipForUsers, "{} - skip filter execution: matched one of the ignored SUBS ({})");
} }
private boolean skipForClientId(String clientId) { private boolean skipForClientId(String clientId) {
if (clientId != null && clientIds.contains(clientId)){ return checkRule(clientId, skipForClients, "{} - skip filter execution: matched one of the ignored CLIENT_IDS ({})");
log.debug("{} - skip filter execution: matched one of the ignored CLIENT_IDS ({})", filterName, clientId); }
private boolean checkRule(String param, Set<String> ruleSet, String logMsg) {
if (param != null && ruleSet.contains(param)){
log.debug(logMsg, filterName, param);
return true; return true;
} }
return false; return false;
} }
private void initializeExecutionRulesLists(AuthProcFilterInitContext ctx) {
initializeExecutionRuleList(ctx, EXECUTE_FOR_CLIENTS, executeForClients);
initializeExecutionRuleList(ctx, SKIP_FOR_CLIENTS, skipForClients);
initializeExecutionRuleList(ctx, CLIENT_IDS, skipForClients);
initializeExecutionRuleList(ctx, EXECUTE_FOR_USERS, executeForUsers);
initializeExecutionRuleList(ctx, SKIP_FOR_USERS, skipForUsers);
initializeExecutionRuleList(ctx, SUBS, skipForUsers);
}
private void initializeExecutionRuleList(AuthProcFilterInitContext ctx, String property, Set<String> list) {
if (ctx.hasProperty(property)) {
String value = ctx.getProperty(property, "");
list.addAll(Arrays.asList(value.split(DELIMITER)));
}
}
} }

View File

@ -3,31 +3,18 @@ package cz.muni.ics.oidc.server.filters;
import cz.muni.ics.oauth2.model.ClientDetailsEntity; import cz.muni.ics.oauth2.model.ClientDetailsEntity;
import cz.muni.ics.oidc.models.Facility; import cz.muni.ics.oidc.models.Facility;
import cz.muni.ics.oidc.models.PerunUser; import cz.muni.ics.oidc.models.PerunUser;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
public class FilterParams { @Getter
@AllArgsConstructor
public class AuthProcFilterCommonVars {
private final ClientDetailsEntity client; private final ClientDetailsEntity client;
private final Facility facility; private final Facility facility;
private final PerunUser user; private final PerunUser user;
public FilterParams(ClientDetailsEntity client, Facility facility, PerunUser user) {
this.client = client;
this.facility = facility;
this.user = user;
}
public ClientDetailsEntity getClient() {
return client;
}
public Facility getFacility() {
return facility;
}
public PerunUser getUser() {
return user;
}
public String getClientIdentifier() { public String getClientIdentifier() {
if (client != null) { if (client != null) {
return client.getClientId(); return client.getClientId();

View File

@ -0,0 +1,55 @@
package cz.muni.ics.oidc.server.filters;
import java.util.Map;
/**
* Class containing common constants used by Perun request filters.
*
* @author Dominik Baranek <baranek@ics.muni.cz>
* @author Dominik Frantisek Bucik <bucik@ics.muni.cz>
*/
public interface AuthProcFilterConstants {
String AUTHORIZE_REQ_PATTERN = "/auth/authorize";
String DEVICE_APPROVE_REQ_PATTERN = "/auth/device/authorize";
String PARAM_CLIENT_ID = "client_id";
String PARAM_SCOPE = "scope";
String PARAM_MESSAGE = "message";
String PARAM_HEADER = "header";
String PARAM_TARGET = "target";
String PARAM_FORCE_AUTHN = "forceAuthn";
String PARAM_PROMPT = "prompt";
String PARAM_REASON = "reason";
String PARAM_ACCEPTED = "accepted";
String PARAM_ACR_VALUES = "acr_values";
String PARAM_POST_LOGOUT_REDIRECT_URI = "post_logout_redirect_uri";
String PARAM_STATE = "state";
String CLIENT_ID_PREFIX = "urn:cesnet:proxyidp:client_id:";
String AARC_IDP_HINT = "aarc_idp_hint";
String IDP_ENTITY_ID_PREFIX = "urn:cesnet:proxyidp:idpentityid:";
String FILTER_PREFIX = "urn:cesnet:proxyidp:filter:";
String EFILTER_PREFIX = "urn:cesnet:proxyidp:efilter:";
String SAML_EPUID = "urn:oid:1.3.6.1.4.1.5923.1.1.1.13";
String SAML_EPPN = "urn:oid:1.3.6.1.4.1.5923.1.1.1.6";
String SAML_EPTID = "urn:oid:1.3.6.1.4.1.5923.1.1.1.10";
String SAML_UID = "urn:oid:0.9.2342.19200300.100.1.1";
String SAML_UNIQUE_IDENTIFIER = "urn:oid:0.9.2342.19200300.100.1.44";
String SAML_PERUN_USERID_IDENTIFIER = "urn:cesnet:proxyidp:attribute:perunUserId";
String REFEDS_MFA = "https://refeds.org/profile/mfa";
String PROMPT_LOGIN = "login";
String PROMPT_SELECT_ACCOUNT = "select_account";
Map<String, String> SAML_IDS = Map.of(
"eppn", SAML_EPPN,
"epuid", SAML_EPUID,
"eptid", SAML_EPTID,
"uid", SAML_UID,
"uniqueIdentifier", SAML_UNIQUE_IDENTIFIER,
"perunUserId", SAML_PERUN_USERID_IDENTIFIER
);
}

View File

@ -0,0 +1,53 @@
package cz.muni.ics.oidc.server.filters;
import cz.muni.ics.oidc.BeanUtil;
import cz.muni.ics.oidc.server.adapters.PerunAdapter;
import cz.muni.ics.oidc.server.configurations.PerunOidcConfig;
import java.util.Properties;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* Class holding parameters for AuthProcFilter instantiation.
*
* @author Dominik Frantisek Bucik <bucik@ics.muni.cz>
*/
@Getter
@AllArgsConstructor
public class AuthProcFilterInitContext {
public static final String PROP_CLASS = "class";
private final String filterName;
private final String filterPropertyPrefix;
private final Properties properties;
private final BeanUtil beanUtil;
public boolean hasProperty(String name) {
return this.properties.containsKey(filterPropertyPrefix + '.' + name);
}
public String getProperty(String name) {
return this.properties.getProperty(filterPropertyPrefix + '.' + name);
}
public String getProperty(String name, String defaultValue) {
if (this.properties.containsKey(filterPropertyPrefix + '.' + name)) {
return this.properties.getProperty(filterPropertyPrefix + '.' + name);
}
return defaultValue;
}
public String getFilterClass() {
return (String) properties.getOrDefault(filterPropertyPrefix + '.' + PROP_CLASS, null);
}
public PerunAdapter getPerunAdapterBean() {
return beanUtil.getBean(PerunAdapter.class);
}
public PerunOidcConfig getPerunOidcConfigBean() {
return beanUtil.getBean(PerunOidcConfig.class);
}
}

View File

@ -1,52 +0,0 @@
package cz.muni.ics.oidc.server.filters;
import cz.muni.ics.oidc.BeanUtil;
import java.util.Properties;
/**
* Class holding parameters for filter instantiation
*
* @author Dominik Frantisek Bucik <bucik@ics.muni.cz>
*/
public class AuthProcFilterParams {
private final String filterName;
private final String propertyPrefix;
private final Properties properties;
private final BeanUtil beanUtil;
public AuthProcFilterParams(String filterName, String propertyPrefix, Properties properties, BeanUtil beanUtil) {
this.filterName = filterName;
this.propertyPrefix = propertyPrefix;
this.properties = properties;
this.beanUtil = beanUtil;
}
public boolean hasProperty(String name) {
return this.properties.containsKey(propertyPrefix + '.' + name);
}
public String getProperty(String name) {
return this.properties.getProperty(propertyPrefix + '.' + name);
}
public String getProperty(String name, String defaultValue) {
if (this.properties.containsKey(propertyPrefix + '.' + name)) {
return this.properties.getProperty(propertyPrefix + '.' + name);
}
return defaultValue;
}
public BeanUtil getBeanUtil() {
return beanUtil;
}
public String getFilterName() {
return filterName;
}
public Properties getProperties() {
return properties;
}
}

View File

@ -1,7 +1,7 @@
package cz.muni.ics.oidc.server.filters; package cz.muni.ics.oidc.server.filters;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.AUTHORIZE_REQ_PATTERN; import static cz.muni.ics.oidc.server.filters.AuthProcFilterConstants.AUTHORIZE_REQ_PATTERN;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.DEVICE_APPROVE_REQ_PATTERN; import static cz.muni.ics.oidc.server.filters.AuthProcFilterConstants.DEVICE_APPROVE_REQ_PATTERN;
import cz.muni.ics.oauth2.model.ClientDetailsEntity; import cz.muni.ics.oauth2.model.ClientDetailsEntity;
import cz.muni.ics.oauth2.service.ClientDetailsEntityService; import cz.muni.ics.oauth2.service.ClientDetailsEntityService;
@ -23,6 +23,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.oauth2.provider.OAuth2RequestFactory; import org.springframework.security.oauth2.provider.OAuth2RequestFactory;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher; import org.springframework.security.web.util.matcher.OrRequestMatcher;
@ -31,7 +32,8 @@ import org.springframework.util.StringUtils;
import org.springframework.web.filter.GenericFilterBean; import org.springframework.web.filter.GenericFilterBean;
/** /**
* This filter calls other Perun filters saved in the PerunFiltersContext * Wrapper filter for the AuthProcFilters in the security chain. Takes care of providing most basic parameters
* and calls the custom AuthProcFilter chain.
* *
* @author Dominik Baranek <baranek@ics.muni.cz> * @author Dominik Baranek <baranek@ics.muni.cz>
* @author Dominik Frantisek Bucik <bucik@ics.muni.cz> * @author Dominik Frantisek Bucik <bucik@ics.muni.cz>
@ -46,29 +48,34 @@ public class AuthProcFiltersContainer extends GenericFilterBean {
private static final RequestMatcher MATCHER = new OrRequestMatcher( private static final RequestMatcher MATCHER = new OrRequestMatcher(
Arrays.asList(AUTHORIZE_MATCHER, AUTHORIZE_ALL_MATCHER, DEVICE_CODE_MATCHER, DEVICE_CODE_ALL_MATCHER)); Arrays.asList(AUTHORIZE_MATCHER, AUTHORIZE_ALL_MATCHER, DEVICE_CODE_MATCHER, DEVICE_CODE_ALL_MATCHER));
@Autowired private final Properties properties;
private Properties coreProperties; private final BeanUtil beanUtil;
private final OAuth2RequestFactory authRequestFactory;
private final ClientDetailsEntityService clientDetailsEntityService;
private final PerunAdapter perunAdapter;
private final SamlProperties samlProperties;
private List<AuthProcFilter> filters;
@Autowired @Autowired
private BeanUtil beanUtil; public AuthProcFiltersContainer(@Qualifier("coreProperties")Properties properties,
BeanUtil beanUtil,
@Autowired OAuth2RequestFactory authRequestFactory,
private OAuth2RequestFactory authRequestFactory; ClientDetailsEntityService clientDetailsEntityService,
PerunAdapter perunAdapter,
@Autowired SamlProperties samlProperties)
private ClientDetailsEntityService clientDetailsEntityService; {
this.properties = properties;
@Autowired this.beanUtil = beanUtil;
private PerunAdapter perunAdapter; this.authRequestFactory = authRequestFactory;
this.clientDetailsEntityService = clientDetailsEntityService;
@Autowired this.perunAdapter = perunAdapter;
private SamlProperties samlProperties; this.samlProperties = samlProperties;
}
private AuthProcFiltersContext perunFiltersContext;
@PostConstruct @PostConstruct
public void postConstruct() { public void postConstruct() {
this.perunFiltersContext = new AuthProcFiltersContext(coreProperties, beanUtil); this.filters = AuthProcFiltersInitializer.initialize(properties, beanUtil);
} }
@Override @Override
@ -80,7 +87,6 @@ public class AuthProcFiltersContainer extends GenericFilterBean {
if (!MATCHER.matches(req)) { if (!MATCHER.matches(req)) {
log.debug("AuthProc filters have been skipped, did not match authorization nor device req URL"); log.debug("AuthProc filters have been skipped, did not match authorization nor device req URL");
} else { } else {
List<AuthProcFilter> filters = perunFiltersContext.getFilters();
if (filters != null && !filters.isEmpty()) { if (filters != null && !filters.isEmpty()) {
ClientDetailsEntity client = FiltersUtils.extractClientFromRequest(req, authRequestFactory, ClientDetailsEntity client = FiltersUtils.extractClientFromRequest(req, authRequestFactory,
clientDetailsEntityService); clientDetailsEntityService);
@ -94,7 +100,7 @@ public class AuthProcFiltersContainer extends GenericFilterBean {
} }
} }
PerunUser user = FiltersUtils.getPerunUser(req, perunAdapter, samlProperties); PerunUser user = FiltersUtils.getPerunUser(req, perunAdapter, samlProperties);
FilterParams params = new FilterParams(client, facility, user); AuthProcFilterCommonVars params = new AuthProcFilterCommonVars(client, facility, user);
for (AuthProcFilter filter : filters) { for (AuthProcFilter filter : filters) {
if (!filter.doFilter(req, res, params)) { if (!filter.doFilter(req, res, params)) {
return; return;

View File

@ -1,91 +0,0 @@
package cz.muni.ics.oidc.server.filters;
import cz.muni.ics.oidc.BeanUtil;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
/**
* Class that contains all custom Perun request filters. Filters are stored in the LinkedList
* and executed in the order they are added to the list.
*
* Filters are configured from configuration file in following way:
* filter.names=filterName1,filterName2,...
*
* @see AuthProcFilter for configuration of filter
*
* @author Dominik Frantisek Bucik <bucik@ics.muni.cz>
*/
@Slf4j
public class AuthProcFiltersContext {
private static final String FILTER_NAMES = "filter.names";
private static final String FILTER_CLASS = ".class";
private static final String PREFIX = "filter.";
private final List<AuthProcFilter> filters;
private final Properties properties;
private final BeanUtil beanUtil;
public AuthProcFiltersContext(Properties properties, BeanUtil beanUtil) {
this.properties = properties;
this.beanUtil = beanUtil;
this.filters = new LinkedList<>();
String filterNames = properties.getProperty(FILTER_NAMES);
log.debug("Filters to be initialized '{}'", filterNames);
log.debug("--------------------------------");
for (String filterName: filterNames.split(",")) {
AuthProcFilter requestFilter = loadFilter(filterName);
filters.add(requestFilter);
log.debug("--------------------------------");
}
}
public List<AuthProcFilter> getFilters() {
return filters;
}
private AuthProcFilter loadFilter(String filterName) {
String propPrefix = AuthProcFiltersContext.PREFIX + filterName;
String filterClass = properties.getProperty(propPrefix + FILTER_CLASS, null);
if (!StringUtils.hasText(filterClass)) {
log.warn("{} - failed to initialized filter: no class has ben configured", filterName);
return null;
}
log.trace("{} - loading class '{}'", filterName, filterClass);
try {
Class<?> rawClazz = Class.forName(filterClass);
if (!AuthProcFilter.class.isAssignableFrom(rawClazz)) {
log.warn("{} - failed to initialized filter: class '{}' does not extend AuthProcFilter",
filterName, filterClass);
return null;
}
@SuppressWarnings("unchecked") Class<AuthProcFilter> clazz = (Class<AuthProcFilter>) rawClazz;
Constructor<AuthProcFilter> constructor = clazz.getConstructor(AuthProcFilterParams.class);
AuthProcFilterParams params = new AuthProcFilterParams(filterName, propPrefix, properties, beanUtil);
return constructor.newInstance(params);
} catch (ClassNotFoundException e) {
log.warn("{} - failed to initialize filter: class '{}' was not found", filterName, filterClass);
log.trace("{} - details:", filterName, e);
return null;
} catch (NoSuchMethodException e) {
log.warn("{} - failed to initialize filter: class '{}' does not have proper constructor",
filterName, filterClass);
log.trace("{} - details:", filterName, e);
return null;
} catch (IllegalAccessException | InvocationTargetException | InstantiationException e) {
log.warn("{} - failed to initialize filter: class '{}' cannot be instantiated", filterName, filterClass);
log.trace("{} - details:", filterName, e);
return null;
}
}
}

View File

@ -0,0 +1,77 @@
package cz.muni.ics.oidc.server.filters;
import cz.muni.ics.oidc.BeanUtil;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
/**
* Initialization class for AuthProcFilters. Takes care of loading the filters and putting them into the custom
* authentication processing chain.
*
* @author Dominik Baranek <baranek@ics.muni.cz>
* @author Dominik Frantisek Bucik <bucik@ics.muni.cz>
*/
@Slf4j
public class AuthProcFiltersInitializer {
private static final String FILTER_NAMES = "filter.names";
private static final String FILTERS_PROP_BASE_PREFIX = "filter.";
public static List<AuthProcFilter> initialize(Properties coreProperties, BeanUtil beanUtil) {
List<AuthProcFilter> filters = new LinkedList<>();
String filterNames = coreProperties.getProperty(FILTER_NAMES);
log.debug("Filters to be initialized '{}'", filterNames);
log.debug("--------------------------------");
for (String filterName: filterNames.split(",")) {
String filterPropertyPrefix = FILTERS_PROP_BASE_PREFIX + filterName;
AuthProcFilterInitContext ctx = new AuthProcFilterInitContext(filterName, filterPropertyPrefix, coreProperties, beanUtil);
AuthProcFilter requestFilter = loadFilter(ctx);
filters.add(requestFilter);
log.debug("--------------------------------");
}
return filters;
}
private static AuthProcFilter loadFilter(AuthProcFilterInitContext ctx) {
String filterClass = ctx.getFilterClass();
if (!StringUtils.hasText(filterClass)) {
log.warn("{} - failed to initialized filter: no class has ben configured", ctx.getFilterName());
return null;
}
log.debug("{} - loading class '{}'", ctx.getFilterName(), filterClass);
try {
Class<?> rawClazz = Class.forName(filterClass);
if (!AuthProcFilter.class.isAssignableFrom(rawClazz)) {
log.warn("{} - failed to initialized filter: class '{}' does not extend AuthProcFilter",
ctx.getFilterName(), filterClass);
return null;
}
@SuppressWarnings("unchecked") Class<AuthProcFilter> clazz = (Class<AuthProcFilter>) rawClazz;
Constructor<AuthProcFilter> constructor = clazz.getConstructor(AuthProcFilterInitContext.class);
return constructor.newInstance(ctx);
} catch (ClassNotFoundException e) {
log.warn("{} - failed to initialize filter: class '{}' was not found", ctx.getFilterName(), filterClass);
log.debug("{} - details:", ctx.getFilterName(), e);
return null;
} catch (NoSuchMethodException e) {
log.warn("{} - failed to initialize filter: class '{}' does not have proper constructor",
ctx.getFilterName(), filterClass);
log.debug("{} - details:", ctx.getFilterName(), e);
return null;
} catch (IllegalAccessException | InvocationTargetException | InstantiationException e) {
log.warn("{} - failed to initialize filter: class '{}' cannot be instantiated", ctx.getFilterName(), filterClass);
log.debug("{} - details:", ctx.getFilterName(), e);
return null;
}
}
}

View File

@ -1,7 +1,7 @@
package cz.muni.ics.oidc.server.filters; package cz.muni.ics.oidc.server.filters;
import static cz.muni.ics.oauth2.web.endpoint.DeviceEndpoint.DEVICE_CODE_SESSION_ATTRIBUTE; import static cz.muni.ics.oauth2.web.endpoint.DeviceEndpoint.DEVICE_CODE_SESSION_ATTRIBUTE;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_FORCE_AUTHN; import static cz.muni.ics.oidc.server.filters.AuthProcFilterConstants.PARAM_FORCE_AUTHN;
import cz.muni.ics.oauth2.model.ClientDetailsEntity; import cz.muni.ics.oauth2.model.ClientDetailsEntity;
import cz.muni.ics.oauth2.model.DeviceCode; import cz.muni.ics.oauth2.model.DeviceCode;
@ -9,8 +9,11 @@ import cz.muni.ics.oauth2.service.ClientDetailsEntityService;
import cz.muni.ics.oidc.models.Facility; import cz.muni.ics.oidc.models.Facility;
import cz.muni.ics.oidc.models.PerunAttributeValue; import cz.muni.ics.oidc.models.PerunAttributeValue;
import cz.muni.ics.oidc.models.PerunUser; import cz.muni.ics.oidc.models.PerunUser;
import cz.muni.ics.oidc.saml.SamlPrincipal;
import cz.muni.ics.oidc.saml.SamlProperties; import cz.muni.ics.oidc.saml.SamlProperties;
import cz.muni.ics.oidc.server.adapters.PerunAdapter; import cz.muni.ics.oidc.server.adapters.PerunAdapter;
import cz.muni.ics.oidc.server.claims.ClaimInitContext;
import cz.muni.ics.oidc.server.claims.ClaimSourceInitContext;
import cz.muni.ics.oidc.server.configurations.FacilityAttrsConfig; import cz.muni.ics.oidc.server.configurations.FacilityAttrsConfig;
import cz.muni.ics.oidc.web.controllers.ControllerUtils; import cz.muni.ics.oidc.web.controllers.ControllerUtils;
import cz.muni.ics.oidc.web.controllers.PerunUnapprovedRegistrationController; import cz.muni.ics.oidc.web.controllers.PerunUnapprovedRegistrationController;
@ -35,6 +38,42 @@ import org.springframework.util.StringUtils;
@Slf4j @Slf4j
public class FiltersUtils { public class FiltersUtils {
public static final String NO_VALUE = null;
public static String fillStringMandatoryProperty(String suffix, AuthProcFilterInitContext ctx) {
String filled = fillStringPropertyOrDefaultVal(ctx.getProperty(suffix, NO_VALUE), NO_VALUE);
if (filled == null) {
throw new IllegalArgumentException(ctx.getFilterName() + " - missing mandatory configuration option: " + suffix);
}
return filled;
}
public static String fillStringPropertyOrDefaultVal(String suffix, AuthProcFilterInitContext ctx, String defaultVal) {
return fillStringPropertyOrDefaultVal(ctx.getProperty(suffix, NO_VALUE), defaultVal);
}
private static String fillStringPropertyOrDefaultVal(String prop, String defaultVal) {
if (StringUtils.hasText(prop)) {
return prop;
} else {
return defaultVal;
}
}
public static boolean fillBooleanPropertyOrDefaultVal(String suffix, AuthProcFilterInitContext ctx, boolean defaultVal) {
return fillBooleanPropertyOrDefaultVal(ctx.getProperty(suffix, NO_VALUE), defaultVal);
}
private static boolean fillBooleanPropertyOrDefaultVal(String prop, boolean defaultVal) {
if (StringUtils.hasText(prop)) {
return Boolean.parseBoolean(prop);
} else {
return defaultVal;
}
}
/** /**
* Create map of request params in format key = name, value = paramValue. * Create map of request params in format key = name, value = paramValue.
* *
@ -173,7 +212,7 @@ public class FiltersUtils {
} else if (!StringUtils.hasText(idAttribute)) { } else if (!StringUtils.hasText(idAttribute)) {
throw new IllegalArgumentException("No identifier from SAML configured"); throw new IllegalArgumentException("No identifier from SAML configured");
} }
String identifierAttrOid = PerunFilterConstants.SAML_IDS.getOrDefault(idAttribute, null); String identifierAttrOid = AuthProcFilterConstants.SAML_IDS.getOrDefault(idAttribute, null);
if (identifierAttrOid == null) { if (identifierAttrOid == null) {
throw new IllegalStateException("SAML credentials has no value for attribute: " + idAttribute); throw new IllegalStateException("SAML credentials has no value for attribute: " + idAttribute);
} }
@ -283,10 +322,11 @@ public class FiltersUtils {
PerunUser user, PerunUser user,
String clientIdentifier, String clientIdentifier,
FacilityAttrsConfig facilityAttrsConfig, FacilityAttrsConfig facilityAttrsConfig,
Map<String, PerunAttributeValue> facilityAttributes,
PerunAdapter perunAdapter, PerunAdapter perunAdapter,
String redirectUrl) String redirectUrl)
{ {
Map<String, PerunAttributeValue> facilityAttributes = perunAdapter.getFacilityAttributeValues(
facility, facilityAttrsConfig.getMembershipAttrNames());
if (facilityAttributes.get(facilityAttrsConfig.getAllowRegistrationAttr()).valueAsBoolean()) { if (facilityAttributes.get(facilityAttrsConfig.getAllowRegistrationAttr()).valueAsBoolean()) {
boolean canRegister = perunAdapter.getAdapterRpc().groupWhereCanRegisterExists(facility); boolean canRegister = perunAdapter.getAdapterRpc().groupWhereCanRegisterExists(facility);
if (canRegister) { if (canRegister) {
@ -316,7 +356,7 @@ public class FiltersUtils {
public static String fillStringMandatoryProperty(String propertyName, public static String fillStringMandatoryProperty(String propertyName,
String filterName, String filterName,
AuthProcFilterParams params) { AuthProcFilterInitContext params) {
String filled = params.getProperty(propertyName); String filled = params.getProperty(propertyName);
if (!StringUtils.hasText(filled)) { if (!StringUtils.hasText(filled)) {
@ -366,4 +406,11 @@ public class FiltersUtils {
return new AbstractMap.SimpleImmutableEntry<>(key, value); return new AbstractMap.SimpleImmutableEntry<>(key, value);
} }
public static String getUserIdentifier(HttpServletRequest req, String identifierSamlAttribute) {
return getExtLogin(getSamlCredential(req), identifierSamlAttribute);
}
public static String getClientId(HttpServletRequest req) {
return req.getParameter(AuthProcFilterConstants.PARAM_CLIENT_ID);
}
} }

View File

@ -1,57 +0,0 @@
package cz.muni.ics.oidc.server.filters;
import java.util.HashMap;
import java.util.Map;
/**
* Class containing common constants used by Perun request filters.
*
* @author Dominik Baranek <baranek@ics.muni.cz>
* @author Dominik Frantisek Bucik <bucik@ics.muni.cz>
*/
public class PerunFilterConstants {
public static final String AUTHORIZE_REQ_PATTERN = "/auth/authorize";
public static final String DEVICE_APPROVE_REQ_PATTERN = "/auth/device/authorize";
public static final String PARAM_CLIENT_ID = "client_id";
public static final String PARAM_SCOPE = "scope";
public static final String PARAM_MESSAGE = "message";
public static final String PARAM_HEADER = "header";
public static final String PARAM_TARGET = "target";
public static final String PARAM_FORCE_AUTHN = "forceAuthn";
public static final String PARAM_PROMPT = "prompt";
public static final String PARAM_REASON = "reason";
public static final String PARAM_ACCEPTED = "accepted";
public static final String PARAM_ACR_VALUES = "acr_values";
public static final String PARAM_POST_LOGOUT_REDIRECT_URI = "post_logout_redirect_uri";
public static final String PARAM_STATE = "state";
public static final String CLIENT_ID_PREFIX = "urn:cesnet:proxyidp:client_id:";
public static final String AARC_IDP_HINT = "aarc_idp_hint";
public static final String IDP_ENTITY_ID_PREFIX = "urn:cesnet:proxyidp:idpentityid:";
public static final String FILTER_PREFIX = "urn:cesnet:proxyidp:filter:";
public static final String EFILTER_PREFIX = "urn:cesnet:proxyidp:efilter:";
public static final String SAML_EPUID = "urn:oid:1.3.6.1.4.1.5923.1.1.1.13";
public static final String SAML_EPPN = "urn:oid:1.3.6.1.4.1.5923.1.1.1.6";
public static final String SAML_EPTID = "urn:oid:1.3.6.1.4.1.5923.1.1.1.10";
public static final String SAML_UID = "urn:oid:0.9.2342.19200300.100.1.1";
public static final String SAML_UNIQUE_IDENTIFIER = "urn:oid:0.9.2342.19200300.100.1.44";
public static final String SAML_PERUN_USERID_IDENTIFIER = "urn:cesnet:proxyidp:attribute:perunUserId";
public static final String REFEDS_MFA = "https://refeds.org/profile/mfa";
public static final String PROMPT_LOGIN = "login";
public static final String PROMPT_SELECT_ACCOUNT = "select_account";
public static final Map<String, String> SAML_IDS = new HashMap<>();
static {
SAML_IDS.put("eppn", SAML_EPPN);
SAML_IDS.put("epuid", SAML_EPUID);
SAML_IDS.put("eptid", SAML_EPTID);
SAML_IDS.put("uid", SAML_UID);
SAML_IDS.put("uniqueIdentifier", SAML_UNIQUE_IDENTIFIER);
SAML_IDS.put("perunUserId", SAML_PERUN_USERID_IDENTIFIER);
}
}

View File

@ -1,33 +0,0 @@
package cz.muni.ics.oidc.server.filters.impl;
import cz.muni.ics.oidc.server.filters.impl.mdc.RemoteAddressMDCFilter;
import cz.muni.ics.oidc.server.filters.impl.mdc.SessionIdMDCFilter;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.slf4j.MDC;
import org.springframework.web.filter.GenericFilterBean;
public class MultiMDCFilter extends GenericFilterBean {
private final RemoteAddressMDCFilter remoteAddressMDCFilter;
private final SessionIdMDCFilter sessionIdMDCFilter;
public MultiMDCFilter() {
this.remoteAddressMDCFilter = new RemoteAddressMDCFilter();
this.sessionIdMDCFilter = new SessionIdMDCFilter();
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException
{
remoteAddressMDCFilter.doFilter(servletRequest);
sessionIdMDCFilter.doFilter(servletRequest);
filterChain.doFilter(servletRequest, servletResponse);
MDC.clear();
}
}

View File

@ -1,17 +1,18 @@
package cz.muni.ics.oidc.server.filters.impl; package cz.muni.ics.oidc.server.filters.impl;
import cz.muni.ics.oidc.BeanUtil; import static cz.muni.ics.oidc.web.controllers.PerunUnapprovedController.UNAPPROVED_AUTHORIZATION;
import cz.muni.ics.oidc.exceptions.ConfigurationException;
import cz.muni.ics.oidc.models.Facility; import cz.muni.ics.oidc.models.Facility;
import cz.muni.ics.oidc.models.PerunAttributeValue; import cz.muni.ics.oidc.models.PerunAttributeValue;
import cz.muni.ics.oidc.models.PerunUser; import cz.muni.ics.oidc.models.PerunUser;
import cz.muni.ics.oidc.server.adapters.PerunAdapter; import cz.muni.ics.oidc.server.adapters.PerunAdapter;
import cz.muni.ics.oidc.server.configurations.FacilityAttrsConfig; import cz.muni.ics.oidc.server.configurations.FacilityAttrsConfig;
import cz.muni.ics.oidc.server.configurations.PerunOidcConfig; import cz.muni.ics.oidc.server.configurations.PerunOidcConfig;
import cz.muni.ics.oidc.server.filters.FilterParams;
import cz.muni.ics.oidc.server.filters.FiltersUtils;
import cz.muni.ics.oidc.server.filters.AuthProcFilter; import cz.muni.ics.oidc.server.filters.AuthProcFilter;
import cz.muni.ics.oidc.server.filters.AuthProcFilterParams; import cz.muni.ics.oidc.server.filters.AuthProcFilterCommonVars;
import cz.muni.ics.oidc.web.controllers.PerunUnapprovedController; import cz.muni.ics.oidc.server.filters.AuthProcFilterInitContext;
import cz.muni.ics.oidc.server.filters.FiltersUtils;
import java.util.Map; import java.util.Map;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
@ -25,44 +26,35 @@ import lombok.extern.slf4j.Slf4j;
* Configuration: * Configuration:
* - based on the configuration of bean "facilityAttrsConfig" * - based on the configuration of bean "facilityAttrsConfig"
* @see FacilityAttrsConfig * @see FacilityAttrsConfig
* @see cz.muni.ics.oidc.server.filters.AuthProcFilter (basic configuration options)
* *
* @author Dominik Frantisek Bucik <bucik@ics.muni.cz> * @author Dominik Frantisek Bucik <bucik@ics.muni.cz>
*/ */
@Slf4j @Slf4j
public class PerunAuthorizationFilter extends AuthProcFilter { public class PerunAuthorizationFilter extends AuthProcFilter {
public static final String APPLIED = "APPLIED_" + PerunAuthorizationFilter.class.getSimpleName();
private final PerunAdapter perunAdapter; private final PerunAdapter perunAdapter;
private final FacilityAttrsConfig facilityAttrsConfig; private final FacilityAttrsConfig facilityAttrsConfig;
private final String filterName;
private final PerunOidcConfig config; private final PerunOidcConfig config;
public PerunAuthorizationFilter(AuthProcFilterParams params) { public PerunAuthorizationFilter(AuthProcFilterInitContext ctx) throws ConfigurationException {
super(params); super(ctx);
BeanUtil beanUtil = params.getBeanUtil(); this.perunAdapter = ctx.getPerunAdapterBean();
this.perunAdapter = beanUtil.getBean(PerunAdapter.class); this.config = ctx.getPerunOidcConfigBean();
this.facilityAttrsConfig = beanUtil.getBean(FacilityAttrsConfig.class); this.facilityAttrsConfig = ctx.getBeanUtil().getBean(FacilityAttrsConfig.class);
this.filterName = params.getFilterName();
this.config = beanUtil.getBean(PerunOidcConfig.class);
} }
@Override @Override
protected String getSessionAppliedParamName() { protected boolean process(HttpServletRequest req, HttpServletResponse res, AuthProcFilterCommonVars params) {
return APPLIED;
}
@Override
protected boolean process(HttpServletRequest req, HttpServletResponse res, FilterParams params) {
Facility facility = params.getFacility(); Facility facility = params.getFacility();
if (facility == null || facility.getId() == null) { if (facility == null || facility.getId() == null) {
log.debug("{} - skip filter execution: no facility provided", filterName); log.debug("{} - skip filter execution: no facility provided", getFilterName());
return true; return true;
} }
PerunUser user = params.getUser(); PerunUser user = params.getUser();
if (user == null || user.getId() == null) { if (user == null || user.getId() == null) {
log.debug("{} - skip filter execution: no user provided", filterName); log.debug("{} - skip filter execution: no user provided", getFilterName());
return true; return true;
} }
@ -78,17 +70,16 @@ public class PerunAuthorizationFilter extends AuthProcFilter {
facility, facilityAttrsConfig.getMembershipAttrNames()); facility, facilityAttrsConfig.getMembershipAttrNames());
if (!facilityAttributes.get(facilityAttrsConfig.getCheckGroupMembershipAttr()).valueAsBoolean()) { if (!facilityAttributes.get(facilityAttrsConfig.getCheckGroupMembershipAttr()).valueAsBoolean()) {
log.debug("{} - skip filter execution: membership check not requested", filterName); log.debug("{} - skip filter execution: membership check not requested", getFilterName());
return true; return true;
} }
if (perunAdapter.canUserAccessBasedOnMembership(facility, user.getId())) { if (perunAdapter.canUserAccessBasedOnMembership(facility, user.getId())) {
log.info("{} - user allowed to access the service", filterName); log.info("{} - user allowed to access the service", getFilterName());
return true; return true;
} else { } else {
FiltersUtils.redirectUserCannotAccess(config.getConfigBean().getIssuer(), response, facility, user, clientIdentifier, FiltersUtils.redirectUserCannotAccess(config.getConfigBean().getIssuer(), response, facility, user,
facilityAttrsConfig, facilityAttributes, perunAdapter, clientIdentifier, facilityAttrsConfig, perunAdapter, UNAPPROVED_AUTHORIZATION);
PerunUnapprovedController.UNAPPROVED_AUTHORIZATION);
return false; return false;
} }
} }

View File

@ -1,19 +1,21 @@
package cz.muni.ics.oidc.server.filters.impl; package cz.muni.ics.oidc.server.filters.impl;
import cz.muni.ics.oidc.BeanUtil; import cz.muni.ics.oidc.PerunConstants;
import cz.muni.ics.oidc.exceptions.ConfigurationException;
import cz.muni.ics.oidc.models.Facility; import cz.muni.ics.oidc.models.Facility;
import cz.muni.ics.oidc.models.PerunAttributeValue; import cz.muni.ics.oidc.models.PerunAttributeValue;
import cz.muni.ics.oidc.server.adapters.PerunAdapter; import cz.muni.ics.oidc.server.adapters.PerunAdapter;
import cz.muni.ics.oidc.server.configurations.PerunOidcConfig; import cz.muni.ics.oidc.server.configurations.PerunOidcConfig;
import cz.muni.ics.oidc.server.filters.FilterParams;
import cz.muni.ics.oidc.server.filters.FiltersUtils;
import cz.muni.ics.oidc.server.filters.AuthProcFilter; import cz.muni.ics.oidc.server.filters.AuthProcFilter;
import cz.muni.ics.oidc.server.filters.AuthProcFilterParams; import cz.muni.ics.oidc.server.filters.AuthProcFilterInitContext;
import cz.muni.ics.oidc.server.filters.AuthProcFilterCommonVars;
import cz.muni.ics.oidc.server.filters.FiltersUtils;
import cz.muni.ics.oidc.web.controllers.ControllerUtils; import cz.muni.ics.oidc.web.controllers.ControllerUtils;
import cz.muni.ics.oidc.web.controllers.PerunUnapprovedController; import cz.muni.ics.oidc.web.controllers.PerunUnapprovedController;
import cz.muni.ics.oidc.web.controllers.RegistrationController; import cz.muni.ics.oidc.web.controllers.RegistrationController;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
@ -26,6 +28,7 @@ import org.springframework.util.StringUtils;
* Otherwise, user can to access the service. * Otherwise, user can to access the service.
* *
* Configuration (replace [name] part with the name defined for the filter): * Configuration (replace [name] part with the name defined for the filter):
* @see cz.muni.ics.oidc.server.filters.AuthProcFilter (basic configuration options)
* <ul> * <ul>
* <li><b>filter.[name].triggerAttr</b> - mapping to attribute which contains flag if this is enabled for facility</li> * <li><b>filter.[name].triggerAttr</b> - mapping to attribute which contains flag if this is enabled for facility</li>
* <li><b>filter.[name].voDefsAttr</b> - mapping to attribute which contains VO(s) to check</li> * <li><b>filter.[name].voDefsAttr</b> - mapping to attribute which contains VO(s) to check</li>
@ -36,8 +39,6 @@ import org.springframework.util.StringUtils;
@Slf4j @Slf4j
public class PerunEnsureVoMember extends AuthProcFilter { public class PerunEnsureVoMember extends AuthProcFilter {
public static final String APPLIED = "APPLIED_" + PerunEnsureVoMember.class.getSimpleName();
private static final String TRIGGER_ATTR = "triggerAttr"; private static final String TRIGGER_ATTR = "triggerAttr";
private static final String VO_DEFS_ATTR = "voDefsAttr"; private static final String VO_DEFS_ATTR = "voDefsAttr";
private static final String LOGIN_URL_ATTR = "loginURL"; private static final String LOGIN_URL_ATTR = "loginURL";
@ -46,50 +47,45 @@ public class PerunEnsureVoMember extends AuthProcFilter {
private final String voDefsAttr; private final String voDefsAttr;
private final String loginUrlAttr; private final String loginUrlAttr;
private final PerunAdapter perunAdapter; private final PerunAdapter perunAdapter;
private final String filterName;
private final PerunOidcConfig perunOidcConfig; private final PerunOidcConfig perunOidcConfig;
public PerunEnsureVoMember(AuthProcFilterParams params) { public PerunEnsureVoMember(AuthProcFilterInitContext ctx) throws ConfigurationException {
super(params); super(ctx);
BeanUtil beanUtil = params.getBeanUtil(); this.perunOidcConfig = ctx.getPerunOidcConfigBean();
this.perunAdapter = ctx.getPerunAdapterBean();
this.perunOidcConfig = beanUtil.getBean(PerunOidcConfig.class); this.triggerAttr = FiltersUtils.fillStringMandatoryProperty(TRIGGER_ATTR, ctx);
this.perunAdapter = beanUtil.getBean(PerunAdapter.class); this.voDefsAttr = FiltersUtils.fillStringMandatoryProperty(VO_DEFS_ATTR, ctx);
this.filterName = params.getFilterName(); this.loginUrlAttr = FiltersUtils.fillStringPropertyOrDefaultVal(LOGIN_URL_ATTR, ctx, null);
this.triggerAttr = FiltersUtils.fillStringMandatoryProperty(TRIGGER_ATTR, filterName, params);
this.voDefsAttr = FiltersUtils.fillStringMandatoryProperty(VO_DEFS_ATTR, filterName, params);
this.loginUrlAttr = params.getProperty(LOGIN_URL_ATTR);
log.debug("{} - initialized filter: {}", filterName, this);
} }
@Override @Override
protected String getSessionAppliedParamName() { protected boolean process(HttpServletRequest req, HttpServletResponse res, AuthProcFilterCommonVars params) {
return APPLIED;
}
@Override
protected boolean process(HttpServletRequest req, HttpServletResponse res, FilterParams params) {
Facility facility = params.getFacility(); Facility facility = params.getFacility();
if (facility == null || facility.getId() == null) { if (facility == null || facility.getId() == null) {
log.debug("{} - skip execution: no facility provided", filterName); log.debug("{} - skip execution: no facility provided", getFilterName());
return true; return true;
} }
Map<String, PerunAttributeValue> attrs = perunAdapter.getFacilityAttributeValues(facility, List<String> attrsToFetch = Arrays.asList(voDefsAttr, triggerAttr, loginUrlAttr);
Arrays.asList(voDefsAttr, triggerAttr, loginUrlAttr)); Map<String, PerunAttributeValue> attrs = perunAdapter.getFacilityAttributeValues(facility, attrsToFetch);
if (attrs == null) {
log.debug("{} - skip filter execution: could not fetch attributes '{}' for facility '{}'",
getFilterName(), attrsToFetch, facility);
return true;
}
PerunAttributeValue triggerAttrValue = attrs.getOrDefault(triggerAttr, null); PerunAttributeValue triggerAttrValue = attrs.getOrDefault(triggerAttr, null);
if (triggerAttrValue == null || !triggerAttrValue.valueAsBoolean()) { if (triggerAttrValue == null || !triggerAttrValue.valueAsBoolean()) {
log.debug("{} - skip execution: attribute '{}' is null or false, which disables the filter", log.debug("{} - skip execution: attribute '{}' is null or false, which disables the filter",
filterName, triggerAttr); getFilterName(), triggerAttr);
return true; return true;
} }
PerunAttributeValue voDefsAttrValue = getVoDefsAttrValue(attrs.getOrDefault(voDefsAttr, null)); PerunAttributeValue voDefsAttrValue = getVoDefsAttrValue(attrs.getOrDefault(voDefsAttr, null));
if (voDefsAttrValue == null) { if (voDefsAttrValue == null) {
log.debug("{} - skip execution: attribute '{}' has null or no value", filterName, voDefsAttr); log.debug("{} - skip execution: attribute '{}' has null or no value", getFilterName(), voDefsAttr);
return true; return true;
} }
String voShortName = voDefsAttrValue.valueAsString(); String voShortName = voDefsAttrValue.valueAsString();
@ -97,7 +93,7 @@ public class PerunEnsureVoMember extends AuthProcFilter {
boolean canAccess = perunAdapter.isUserInVo(params.getUser().getId(), voShortName); boolean canAccess = perunAdapter.isUserInVo(params.getUser().getId(), voShortName);
if (canAccess) { if (canAccess) {
log.debug("{} - user allowed to continue", filterName); log.debug("{} - user allowed to continue", getFilterName());
return true; return true;
} else { } else {
redirect(res, getLoginUrl(facility.getId()), voShortName); redirect(res, getLoginUrl(facility.getId()), voShortName);
@ -144,10 +140,11 @@ public class PerunEnsureVoMember extends AuthProcFilter {
private void redirectDirectly(HttpServletResponse res, String loginUrl, String voShortName) { private void redirectDirectly(HttpServletResponse res, String loginUrl, String voShortName) {
String registrarUrl = perunOidcConfig.getRegistrarUrl(); String registrarUrl = perunOidcConfig.getRegistrarUrl();
Map<String, String> params = new HashMap<>(); Map<String, String> params = new HashMap<>();
params.put("vo", voShortName); params.put(PerunConstants.REGISTRAR_PARAM_VO, voShortName);
if (StringUtils.hasText(loginUrl)) { if (StringUtils.hasText(loginUrl)) {
params.put("targetnew", loginUrl); params.put(PerunConstants.REGISTRAR_TARGET_NEW, loginUrl);
params.put("targetexisting", loginUrl); params.put(PerunConstants.REGISTRAR_TARGET_EXISTING, loginUrl);
params.put(PerunConstants.REGISTRAR_TARGET_EXTENDED, loginUrl);
} }
String target = ControllerUtils.createUrl(registrarUrl, params); String target = ControllerUtils.createUrl(registrarUrl, params);
@ -156,7 +153,7 @@ public class PerunEnsureVoMember extends AuthProcFilter {
params.put(RegistrationController.PARAM_TARGET, target); params.put(RegistrationController.PARAM_TARGET, target);
String redirectUrl = ControllerUtils.createUrl(url, params); String redirectUrl = ControllerUtils.createUrl(url, params);
log.debug("{} - redirecting user to '{}'", filterName, redirectUrl); log.debug("{} - redirecting user to '{}'", getFilterName(), redirectUrl);
res.reset(); res.reset();
res.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); res.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
res.setHeader(HttpHeaders.LOCATION, redirectUrl); res.setHeader(HttpHeaders.LOCATION, redirectUrl);
@ -166,7 +163,7 @@ public class PerunEnsureVoMember extends AuthProcFilter {
String redirectUrl = ControllerUtils.constructRequestUrl(perunOidcConfig, String redirectUrl = ControllerUtils.constructRequestUrl(perunOidcConfig,
PerunUnapprovedController.UNAPPROVED_ENSURE_VO_MAPPING); PerunUnapprovedController.UNAPPROVED_ENSURE_VO_MAPPING);
log.debug("{} - redirecting user to '{}'", filterName, redirectUrl); log.debug("{} - redirecting user to '{}'", getFilterName(), redirectUrl);
res.reset(); res.reset();
res.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); res.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
res.setHeader(HttpHeaders.LOCATION, redirectUrl); res.setHeader(HttpHeaders.LOCATION, redirectUrl);

View File

@ -4,6 +4,7 @@ import static cz.muni.ics.oidc.web.controllers.AupController.APPROVED;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import cz.muni.ics.oidc.BeanUtil; import cz.muni.ics.oidc.BeanUtil;
import cz.muni.ics.oidc.exceptions.ConfigurationException;
import cz.muni.ics.oidc.models.Aup; import cz.muni.ics.oidc.models.Aup;
import cz.muni.ics.oidc.models.Facility; import cz.muni.ics.oidc.models.Facility;
import cz.muni.ics.oidc.models.PerunAttribute; import cz.muni.ics.oidc.models.PerunAttribute;
@ -12,10 +13,10 @@ import cz.muni.ics.oidc.models.PerunUser;
import cz.muni.ics.oidc.saml.SamlProperties; import cz.muni.ics.oidc.saml.SamlProperties;
import cz.muni.ics.oidc.server.adapters.PerunAdapter; import cz.muni.ics.oidc.server.adapters.PerunAdapter;
import cz.muni.ics.oidc.server.configurations.PerunOidcConfig; import cz.muni.ics.oidc.server.configurations.PerunOidcConfig;
import cz.muni.ics.oidc.server.filters.FilterParams;
import cz.muni.ics.oidc.server.filters.FiltersUtils;
import cz.muni.ics.oidc.server.filters.AuthProcFilter; import cz.muni.ics.oidc.server.filters.AuthProcFilter;
import cz.muni.ics.oidc.server.filters.AuthProcFilterParams; import cz.muni.ics.oidc.server.filters.AuthProcFilterCommonVars;
import cz.muni.ics.oidc.server.filters.AuthProcFilterInitContext;
import cz.muni.ics.oidc.server.filters.FiltersUtils;
import cz.muni.ics.oidc.web.controllers.AupController; import cz.muni.ics.oidc.web.controllers.AupController;
import java.io.IOException; import java.io.IOException;
import java.text.ParseException; import java.text.ParseException;
@ -36,6 +37,7 @@ import org.springframework.util.StringUtils;
* AUP filter checks if there are new AUPs which user hasn't accepted yet and forces him to do that. * AUP filter checks if there are new AUPs which user hasn't accepted yet and forces him to do that.
* *
* Configuration (replace [name] part with the name defined for the filter): * Configuration (replace [name] part with the name defined for the filter):
* @see cz.muni.ics.oidc.server.filters.AuthProcFilter (basic configuration options)
* <ul> * <ul>
* <li><b>filter.[name].orgAupsAttrName</b> - Mapping to Perun entityless attribute containing organization AUPs</li> * <li><b>filter.[name].orgAupsAttrName</b> - Mapping to Perun entityless attribute containing organization AUPs</li>
* <li><b>filter.[name].userAupsAttrName</b> - Mapping to Perun user attribute containing list of AUPS approved by user</li> * <li><b>filter.[name].userAupsAttrName</b> - Mapping to Perun user attribute containing list of AUPS approved by user</li>
@ -52,8 +54,6 @@ import org.springframework.util.StringUtils;
@Slf4j @Slf4j
public class PerunForceAupFilter extends AuthProcFilter { public class PerunForceAupFilter extends AuthProcFilter {
public static final String APPLIED = "APPLIED_" + PerunForceAupFilter.class.getSimpleName();
private static final String DATE_FORMAT = "yyyy-MM-dd"; private static final String DATE_FORMAT = "yyyy-MM-dd";
/* CONFIGURATION PROPERTIES */ /* CONFIGURATION PROPERTIES */
@ -75,46 +75,39 @@ public class PerunForceAupFilter extends AuthProcFilter {
private final PerunAdapter perunAdapter; private final PerunAdapter perunAdapter;
private final PerunOidcConfig perunOidcConfig; private final PerunOidcConfig perunOidcConfig;
private final SamlProperties samlProperties; private final SamlProperties samlProperties;
private final String filterName;
public PerunForceAupFilter(AuthProcFilterParams params) { public PerunForceAupFilter(AuthProcFilterInitContext ctx) throws ConfigurationException {
super(params); super(ctx);
BeanUtil beanUtil = params.getBeanUtil(); BeanUtil beanUtil = ctx.getBeanUtil();
this.perunAdapter = beanUtil.getBean(PerunAdapter.class); this.perunAdapter = ctx.getPerunAdapterBean();
this.perunOidcConfig = beanUtil.getBean(PerunOidcConfig.class); this.perunOidcConfig = ctx.getPerunOidcConfigBean();
this.samlProperties = beanUtil.getBean(SamlProperties.class); this.samlProperties = beanUtil.getBean(SamlProperties.class);
this.perunOrgAupsAttrName = params.getProperty(ORG_AUPS_ATTR_NAME); this.perunOrgAupsAttrName = FiltersUtils.fillStringMandatoryProperty(ORG_AUPS_ATTR_NAME, ctx);
this.perunUserAupsAttrName = params.getProperty(USER_AUPS_ATTR_NAME); this.perunUserAupsAttrName = FiltersUtils.fillStringMandatoryProperty(USER_AUPS_ATTR_NAME, ctx);
this.perunVoAupAttrName = params.getProperty(VO_AUP_ATTR_NAME); this.perunVoAupAttrName = FiltersUtils.fillStringMandatoryProperty(VO_AUP_ATTR_NAME, ctx);
this.perunFacilityRequestedAupsAttrName = params.getProperty(FACILITY_REQUESTED_AUPS_ATTR_NAME); this.perunFacilityRequestedAupsAttrName = FiltersUtils.fillStringMandatoryProperty(FACILITY_REQUESTED_AUPS_ATTR_NAME, ctx);
this.perunFacilityVoShortNamesAttrName = params.getProperty(VO_SHORT_NAMES_ATTR_NAME); this.perunFacilityVoShortNamesAttrName = FiltersUtils.fillStringMandatoryProperty(VO_SHORT_NAMES_ATTR_NAME, ctx);
this.filterName = params.getFilterName();
} }
@Override @Override
protected String getSessionAppliedParamName() { protected boolean process(HttpServletRequest req, HttpServletResponse res, AuthProcFilterCommonVars params) throws IOException {
return APPLIED;
}
@Override
protected boolean process(HttpServletRequest req, HttpServletResponse res, FilterParams params) throws IOException {
if (req.getSession() != null && req.getSession().getAttribute(APPROVED) != null) { if (req.getSession() != null && req.getSession().getAttribute(APPROVED) != null) {
req.getSession().removeAttribute(APPROVED); req.getSession().removeAttribute(APPROVED);
log.debug("{} - skip filter execution: aups are already approved, check at next access to the service due" + log.debug("{} - skip filter execution: aups are already approved, check at next access to the service due" +
" to a delayed propagation to LDAP", filterName); " to a delayed propagation to LDAP", getFilterName());
return true; return true;
} }
PerunUser user = FiltersUtils.getPerunUser(req, perunAdapter, samlProperties); PerunUser user = FiltersUtils.getPerunUser(req, perunAdapter, samlProperties);
if (user == null || user.getId() == null) { if (user == null || user.getId() == null) {
log.debug("{} - skip filter execution: no user provider", filterName); log.debug("{} - skip filter execution: no user provider", getFilterName());
return true; return true;
} }
Facility facility = params.getFacility(); Facility facility = params.getFacility();
if (facility == null || facility.getId() == null) { if (facility == null || facility.getId() == null) {
log.debug("{} - skip filter execution: no facility provider", filterName); log.debug("{} - skip filter execution: no facility provider", getFilterName());
return true; return true;
} }
@ -124,13 +117,13 @@ public class PerunForceAupFilter extends AuthProcFilter {
if (facilityAttributes == null) { if (facilityAttributes == null) {
log.debug("{} - skip filter execution: could not fetch attributes '{}' for facility '{}'", log.debug("{} - skip filter execution: could not fetch attributes '{}' for facility '{}'",
filterName, attrsToFetch, facility); getFilterName(), attrsToFetch, facility);
return true; return true;
} else if (!facilityAttributes.containsKey(perunFacilityRequestedAupsAttrName) && } else if (!facilityAttributes.containsKey(perunFacilityRequestedAupsAttrName) &&
!facilityAttributes.containsKey(perunFacilityVoShortNamesAttrName)) !facilityAttributes.containsKey(perunFacilityVoShortNamesAttrName))
{ {
log.debug("{} - skip filter execution: could not fetch required attributes '{}' and '{}' for facility '{}'", log.debug("{} - skip filter execution: could not fetch required attributes '{}' and '{}' for facility '{}'",
filterName, perunFacilityRequestedAupsAttrName, perunFacilityVoShortNamesAttrName, facility); getFilterName(), perunFacilityRequestedAupsAttrName, perunFacilityVoShortNamesAttrName, facility);
return true; return true;
} }
@ -139,30 +132,36 @@ public class PerunForceAupFilter extends AuthProcFilter {
try { try {
newAups = getAupsToApprove(user, facilityAttributes); newAups = getAupsToApprove(user, facilityAttributes);
} catch (ParseException | IOException e) { } catch (ParseException | IOException e) {
log.warn("{} - caught parse exception when processing AUPs to approve", filterName); log.warn("{} - caught parse exception when processing AUPs to approve", getFilterName());
log.trace("{} - details:", filterName, e); log.debug("{} - details:", getFilterName(), e);
return true; return true;
} }
if (!newAups.isEmpty()) { if (!newAups.isEmpty()) {
log.debug("{} - user has to approve some AUPs", filterName); log.info("{} - user has to approve some AUPs", getFilterName());
log.trace("{} - AUPS to be approved: '{}'", filterName, newAups); log.debug("{} - AUPS to be approved: '{}'", getFilterName(), newAups);
String newAupsString = mapper.writeValueAsString(newAups); redirectToApproval(req, res, newAups, user);
req.getSession().setAttribute(AupController.RETURN_URL, req.getRequestURI()
.replace(req.getContextPath(), "") + '?' + req.getQueryString());
req.getSession().setAttribute(AupController.NEW_AUPS, newAupsString);
req.getSession().setAttribute(AupController.USER_ATTR, perunUserAupsAttrName);
log.debug("{} - redirecting user '{}' to AUPs approval page", filterName, user);
res.sendRedirect(req.getContextPath() + '/' + AupController.URL);
return false; return false;
} }
log.debug("{} - no need to approve any AUPs", filterName); log.debug("{} - no need to approve any AUPs", getFilterName());
return true; return true;
} }
private void redirectToApproval(HttpServletRequest req, HttpServletResponse res, Map<String, Aup> newAups,
PerunUser user) throws IOException
{
String newAupsString = mapper.writeValueAsString(newAups);
req.getSession().setAttribute(AupController.RETURN_URL, req.getRequestURI()
.replace(req.getContextPath(), "") + '?' + req.getQueryString());
req.getSession().setAttribute(AupController.NEW_AUPS, newAupsString);
req.getSession().setAttribute(AupController.USER_ATTR, perunUserAupsAttrName);
log.debug("{} - redirecting user '{}' to AUPs approval page", getFilterName(), user);
res.sendRedirect(req.getContextPath() + '/' + AupController.URL);
}
private Map<String, Aup> getAupsToApprove(PerunUser user, Map<String, PerunAttributeValue> facilityAttributes) private Map<String, Aup> getAupsToApprove(PerunUser user, Map<String, PerunAttributeValue> facilityAttributes)
throws ParseException, IOException throws ParseException, IOException
{ {
@ -220,12 +219,12 @@ public class PerunForceAupFilter extends AuthProcFilter {
continue; continue;
} }
} }
log.debug("{} - need to approve AUP with key '{}' ({})", filterName, keyToVoAup.getKey(), voLatestAup); log.debug("{} - need to approve AUP with key '{}' ({})", getFilterName(), keyToVoAup.getKey(), voLatestAup);
aupsToApprove.put(keyToVoAup.getKey(), voLatestAup); aupsToApprove.put(keyToVoAup.getKey(), voLatestAup);
} }
} }
log.trace("{} - VO AUPs to approve: {}", filterName, aupsToApprove); log.trace("{} - VO AUPs to approve: {}", getFilterName(), aupsToApprove);
return aupsToApprove; return aupsToApprove;
} }
@ -246,7 +245,7 @@ public class PerunForceAupFilter extends AuthProcFilter {
} }
} }
} }
log.debug("{} - Mapped ORG aups: {}", filterName, orgAups); log.debug("{} - Mapped ORG aups: {}", getFilterName(), orgAups);
if (!orgAups.isEmpty()) { if (!orgAups.isEmpty()) {
for (String requiredOrgAupKey : requestedAups) { for (String requiredOrgAupKey : requestedAups) {
@ -260,12 +259,12 @@ public class PerunForceAupFilter extends AuthProcFilter {
continue; continue;
} }
} }
log.debug("{} - need to approve AUP with key '{}' ({})", filterName, requiredOrgAupKey, orgLatestAup); log.debug("{} - need to approve AUP with key '{}' ({})", getFilterName(), requiredOrgAupKey, orgLatestAup);
aupsToApprove.put(requiredOrgAupKey, orgLatestAup); aupsToApprove.put(requiredOrgAupKey, orgLatestAup);
} }
} }
log.debug("{} - ORG AUPs to approve: {}", filterName, aupsToApprove); log.debug("{} - ORG AUPs to approve: {}", getFilterName(), aupsToApprove);
return aupsToApprove; return aupsToApprove;
} }

View File

@ -1,147 +0,0 @@
package cz.muni.ics.oidc.server.filters.impl;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_FORCE_AUTHN;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_REASON;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_SCOPE;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_TARGET;
import static cz.muni.ics.oidc.web.controllers.PerunUnapprovedController.REASON_EXPIRED;
import static cz.muni.ics.oidc.web.controllers.PerunUnapprovedController.REASON_NOT_SET;
import cz.muni.ics.oidc.BeanUtil;
import cz.muni.ics.oidc.models.PerunAttributeValue;
import cz.muni.ics.oidc.models.PerunUser;
import cz.muni.ics.oidc.server.adapters.PerunAdapter;
import cz.muni.ics.oidc.server.configurations.PerunOidcConfig;
import cz.muni.ics.oidc.server.filters.FilterParams;
import cz.muni.ics.oidc.server.filters.FiltersUtils;
import cz.muni.ics.oidc.server.filters.AuthProcFilter;
import cz.muni.ics.oidc.server.filters.AuthProcFilterParams;
import cz.muni.ics.oidc.web.controllers.ControllerUtils;
import cz.muni.ics.oidc.web.controllers.PerunUnapprovedController;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpHeaders;
/**
* This filter verifies that user attribute isCesnetEligible is not older than given time frame.
* In case the value is older, denies access to the service and forces user to use verified identity.
* Otherwise, user can to access the service.
*
* Configuration (replace [name] part with the name defined for the filter):
* <ul>
* <li><b>filter.[name].isCesnetEligibleAttr</b> - mapping to isCesnetEligible attribute</li>
* <li><b>filter.[name].validityPeriod</b> - specify in months, how long the value can be old, if no value
* or invalid value has been provided, defaults to 12 months</li>
* </ul>
* @author Dominik Frantisek Bucik <bucik@ics.muni.cz>
*/
@Slf4j
public class PerunIsCesnetEligibleFilter extends AuthProcFilter {
public static final String APPLIED = "APPLIED_" + PerunIsCesnetEligibleFilter.class.getSimpleName();
/* CONFIGURATION PROPERTIES */
private static final String IS_CESNET_ELIGIBLE_ATTR_NAME = "isCesnetEligibleAttr";
private static final String IS_CESNET_ELIGIBLE_SCOPE = "isCesnetEligibleScope";
private static final String VALIDITY_PERIOD = "validityPeriod";
private static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
private final String isCesnetEligibleAttrName;
private final String triggerScope;
private final int validityPeriod;
/* END OF CONFIGURATION PROPERTIES */
private final PerunOidcConfig config;
private final PerunAdapter perunAdapter;
private final String filterName;
public PerunIsCesnetEligibleFilter(AuthProcFilterParams params) {
super(params);
BeanUtil beanUtil = params.getBeanUtil();
this.config = beanUtil.getBean(PerunOidcConfig.class);
this.perunAdapter = beanUtil.getBean(PerunAdapter.class);
this.isCesnetEligibleAttrName = params.getProperty(IS_CESNET_ELIGIBLE_ATTR_NAME);
this.triggerScope = params.getProperty(IS_CESNET_ELIGIBLE_SCOPE);
int validityPeriodParam = 12;
if (params.hasProperty(VALIDITY_PERIOD)) {
try {
validityPeriodParam = Integer.parseInt(params.getProperty(VALIDITY_PERIOD));
} catch (NumberFormatException ignored) {
//no problem, we have default value
}
}
this.validityPeriod = validityPeriodParam;
this.filterName = params.getFilterName();
}
@Override
protected String getSessionAppliedParamName() {
return APPLIED;
}
@Override
protected boolean process(HttpServletRequest req, HttpServletResponse res, FilterParams params) {
if (!FiltersUtils.isScopePresent(req.getParameter(PARAM_SCOPE), triggerScope)) {
log.debug("{} - skip execution: scope '{}' is not present in request", filterName, triggerScope);
return true;
}
PerunUser user = params.getUser();
if (user == null || user.getId() == null) {
log.debug("{} - skip execution: no user provider", filterName);
return true;
}
String reason = REASON_NOT_SET;
PerunAttributeValue attrValue = perunAdapter.getUserAttributeValue(user.getId(), isCesnetEligibleAttrName);
if (attrValue != null) {
LocalDateTime timeStamp;
try {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_TIME_FORMAT);
timeStamp = LocalDateTime.parse(attrValue.valueAsString(), formatter);
} catch (DateTimeParseException e) {
log.warn("{} - could not parse timestamp from attribute '{}' value: '{}'",
filterName, isCesnetEligibleAttrName, attrValue.valueAsString());
log.debug("{} - skip execution: no timestamp to compare to", filterName);
log.trace("{} - details:", filterName, e);
return true;
}
LocalDateTime now = LocalDateTime.now();
if (now.minusMonths(validityPeriod).isBefore(timeStamp)) {
log.debug("{} - attribute '{}' value is valid", filterName, isCesnetEligibleAttrName);
return true;
} else {
reason = REASON_EXPIRED;
}
}
log.debug("{} - attribute '{}' value is invalid, stop user at this point", filterName, attrValue);
this.redirect(req, res, reason);
return false;
}
private void redirect(HttpServletRequest req, HttpServletResponse res, String reason) {
Map<String, String> params = new HashMap<>();
String targetURL = FiltersUtils.buildRequestURL(req, Collections.singletonMap(PARAM_FORCE_AUTHN, "true"));
params.put(PARAM_TARGET, targetURL);
params.put(PARAM_REASON, reason);
String redirectUrl = ControllerUtils.createRedirectUrl(config.getConfigBean().getIssuer(),
PerunUnapprovedController.UNAPPROVED_IS_CESNET_ELIGIBLE_MAPPING, params);
log.debug("{} - redirecting user to unapproved: URL '{}'", filterName, redirectUrl);
res.reset();
res.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
res.setHeader(HttpHeaders.LOCATION, redirectUrl);
}
}

View File

@ -1,17 +1,17 @@
package cz.muni.ics.oidc.server.filters.impl; package cz.muni.ics.oidc.server.filters.impl;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_TARGET; import static cz.muni.ics.oidc.server.filters.AuthProcFilterConstants.PARAM_TARGET;
import static cz.muni.ics.oidc.web.controllers.IsTestSpController.IS_TEST_SP_APPROVED_SESS; import static cz.muni.ics.oidc.web.controllers.IsTestSpController.IS_TEST_SP_APPROVED_SESS;
import cz.muni.ics.oidc.BeanUtil; import cz.muni.ics.oidc.exceptions.ConfigurationException;
import cz.muni.ics.oidc.models.Facility; import cz.muni.ics.oidc.models.Facility;
import cz.muni.ics.oidc.models.PerunAttributeValue; import cz.muni.ics.oidc.models.PerunAttributeValue;
import cz.muni.ics.oidc.server.adapters.PerunAdapter; import cz.muni.ics.oidc.server.adapters.PerunAdapter;
import cz.muni.ics.oidc.server.configurations.PerunOidcConfig; import cz.muni.ics.oidc.server.configurations.PerunOidcConfig;
import cz.muni.ics.oidc.server.filters.FilterParams;
import cz.muni.ics.oidc.server.filters.FiltersUtils;
import cz.muni.ics.oidc.server.filters.AuthProcFilter; import cz.muni.ics.oidc.server.filters.AuthProcFilter;
import cz.muni.ics.oidc.server.filters.AuthProcFilterParams; import cz.muni.ics.oidc.server.filters.AuthProcFilterInitContext;
import cz.muni.ics.oidc.server.filters.AuthProcFilterCommonVars;
import cz.muni.ics.oidc.server.filters.FiltersUtils;
import cz.muni.ics.oidc.web.controllers.ControllerUtils; import cz.muni.ics.oidc.web.controllers.ControllerUtils;
import cz.muni.ics.oidc.web.controllers.IsTestSpController; import cz.muni.ics.oidc.web.controllers.IsTestSpController;
import java.io.IOException; import java.io.IOException;
@ -27,8 +27,9 @@ import org.apache.http.HttpHeaders;
* Otherwise, user can to access the service. * Otherwise, user can to access the service.
* *
* Configuration (replace [name] part with the name defined for the filter): * Configuration (replace [name] part with the name defined for the filter):
* @see cz.muni.ics.oidc.server.filters.AuthProcFilter (basic configuration options)
* <ul> * <ul>
* <li><b>filter.[name].isTestSpAttr</b> - mapping to isCesnetEligible attribute</li> * <li><b>filter.[name].isTestSpAttr</b> - mapping to isTestSp attribute</li>
* </ul> * </ul>
* @author Dominik Frantisek Bucik <bucik@ics.muni.cz> * @author Dominik Frantisek Bucik <bucik@ics.muni.cz>
* @author Pavol Pluta <500348@mail.muni.cz> * @author Pavol Pluta <500348@mail.muni.cz>
@ -36,50 +37,40 @@ import org.apache.http.HttpHeaders;
@Slf4j @Slf4j
public class PerunIsTestSpFilter extends AuthProcFilter { public class PerunIsTestSpFilter extends AuthProcFilter {
public static final String APPLIED = "APPLIED_" + PerunIsTestSpFilter.class.getSimpleName();
private static final String IS_TEST_SP_ATTR_NAME = "isTestSpAttr"; private static final String IS_TEST_SP_ATTR_NAME = "isTestSpAttr";
private final String isTestSpAttrName; private final String isTestSpAttrName;
private final PerunAdapter perunAdapter; private final PerunAdapter perunAdapter;
private final String filterName;
private final PerunOidcConfig config; private final PerunOidcConfig config;
public PerunIsTestSpFilter(AuthProcFilterParams params) { public PerunIsTestSpFilter(AuthProcFilterInitContext ctx) throws ConfigurationException {
super(params); super(ctx);
BeanUtil beanUtil = params.getBeanUtil(); this.perunAdapter = ctx.getPerunAdapterBean();
this.perunAdapter = beanUtil.getBean(PerunAdapter.class); this.config = ctx.getPerunOidcConfigBean();
this.isTestSpAttrName = params.getProperty(IS_TEST_SP_ATTR_NAME); this.isTestSpAttrName = FiltersUtils.fillStringMandatoryProperty(IS_TEST_SP_ATTR_NAME, ctx);
this.filterName = params.getFilterName();
this.config = beanUtil.getBean(PerunOidcConfig.class);
} }
@Override @Override
protected String getSessionAppliedParamName() { protected boolean process(HttpServletRequest req, HttpServletResponse res, AuthProcFilterCommonVars params) throws IOException {
return APPLIED;
}
@Override
protected boolean process(HttpServletRequest req, HttpServletResponse res, FilterParams params) throws IOException {
Facility facility = params.getFacility(); Facility facility = params.getFacility();
if (facility == null || facility.getId() == null) { if (facility == null || facility.getId() == null) {
log.debug("{} - skip execution: no facility provided", filterName); log.debug("{} - skip execution: no facility provided", getFilterName());
return true; return true;
} else if (testSpWarningApproved(req)){ } else if (testSpWarningApproved(req)){
log.debug("{} - skip execution: warning already approved", filterName); log.debug("{} - skip execution: warning already approved", getFilterName());
return true; return true;
} }
PerunAttributeValue attrValue = perunAdapter.getFacilityAttributeValue(facility.getId(), isTestSpAttrName); PerunAttributeValue attrValue = perunAdapter.getFacilityAttributeValue(facility.getId(), isTestSpAttrName);
if (attrValue == null) { if (attrValue == null) {
log.debug("{} - skip execution: attribute {} has null value", filterName, isTestSpAttrName); log.debug("{} - skip execution: attribute {} has null value", getFilterName(), isTestSpAttrName);
return true; return true;
} else if (attrValue.valueAsBoolean()) { } else if (attrValue.valueAsBoolean()) {
log.debug("{} - redirecting user to test SP warning page", filterName); log.debug("{} - redirecting user to test SP warning page", getFilterName());
this.redirect(req, res); this.redirect(req, res);
return false; return false;
} }
log.debug("{} - service is not testing, let user access it", filterName); log.debug("{} - service is not testing, let user access it", getFilterName());
return true; return true;
} }
@ -102,7 +93,7 @@ public class PerunIsTestSpFilter extends AuthProcFilter {
params.put(PARAM_TARGET, targetURL); params.put(PARAM_TARGET, targetURL);
String redirectUrl = ControllerUtils.createRedirectUrl(config.getConfigBean().getIssuer(), String redirectUrl = ControllerUtils.createRedirectUrl(config.getConfigBean().getIssuer(),
IsTestSpController.MAPPING, params); IsTestSpController.MAPPING, params);
log.debug("{} - redirecting user to testSP warning page: {}", filterName, redirectUrl); log.debug("{} - redirecting user to testSP warning page: {}", getFilterName(), redirectUrl);
res.reset(); res.reset();
res.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); res.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
res.setHeader(HttpHeaders.LOCATION, redirectUrl); res.setHeader(HttpHeaders.LOCATION, redirectUrl);

View File

@ -1,11 +1,12 @@
package cz.muni.ics.oidc.server.filters.impl; package cz.muni.ics.oidc.server.filters.impl;
import cz.muni.ics.oauth2.model.ClientDetailsEntity; import cz.muni.ics.oauth2.model.ClientDetailsEntity;
import cz.muni.ics.oidc.exceptions.ConfigurationException;
import cz.muni.ics.oidc.models.PerunUser; import cz.muni.ics.oidc.models.PerunUser;
import cz.muni.ics.oidc.saml.SamlProperties; import cz.muni.ics.oidc.saml.SamlProperties;
import cz.muni.ics.oidc.server.filters.AuthProcFilter; import cz.muni.ics.oidc.server.filters.AuthProcFilter;
import cz.muni.ics.oidc.server.filters.AuthProcFilterParams; import cz.muni.ics.oidc.server.filters.AuthProcFilterInitContext;
import cz.muni.ics.oidc.server.filters.FilterParams; import cz.muni.ics.oidc.server.filters.AuthProcFilterCommonVars;
import cz.muni.ics.oidc.server.filters.FiltersUtils; import cz.muni.ics.oidc.server.filters.FiltersUtils;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
@ -13,29 +14,23 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.security.saml.SAMLCredential; import org.springframework.security.saml.SAMLCredential;
/** /**
* This filter logs information about the user who has logged in INFO level in the format: * This filter logs information about the user who has logged in INFO level in the format
* 'User ID: {}, User identifier: {}, User name: {}, service ID: {}, service name: {}'. * {} - user_id '{}', user_identifier '{}', user_name '{}', service_identifier '{}', service_name: '{}'.
* @see cz.muni.ics.oidc.server.filters.AuthProcFilter (basic configuration options)
* @author Dominik Frantisek Bucik <bucik@ics.muni.cz> * @author Dominik Frantisek Bucik <bucik@ics.muni.cz>
*/ */
@Slf4j @Slf4j
public class PerunLogIdentityFilter extends AuthProcFilter { public class PerunLogIdentityFilter extends AuthProcFilter {
public static final String APPLIED = "APPLIED_" + PerunLogIdentityFilter.class.getSimpleName();
private final String userIdentifierAttr; private final String userIdentifierAttr;
public PerunLogIdentityFilter(AuthProcFilterParams params) { public PerunLogIdentityFilter(AuthProcFilterInitContext params) throws ConfigurationException {
super(params); super(params);
userIdentifierAttr = params.getBeanUtil().getBean(SamlProperties.class).getUserIdentifierAttribute(); userIdentifierAttr = params.getBeanUtil().getBean(SamlProperties.class).getUserIdentifierAttribute();
} }
@Override @Override
protected String getSessionAppliedParamName() { protected boolean process(HttpServletRequest req, HttpServletResponse res, AuthProcFilterCommonVars params) {
return APPLIED;
}
@Override
protected boolean process(HttpServletRequest req, HttpServletResponse res, FilterParams params) {
PerunUser user = params.getUser(); PerunUser user = params.getUser();
ClientDetailsEntity client = params.getClient(); ClientDetailsEntity client = params.getClient();
SAMLCredential samlCredential = FiltersUtils.getSamlCredential(req); SAMLCredential samlCredential = FiltersUtils.getSamlCredential(req);
@ -57,8 +52,8 @@ public class PerunLogIdentityFilter extends AuthProcFilter {
identifier = FiltersUtils.getExtLogin(samlCredential, userIdentifierAttr); identifier = FiltersUtils.getExtLogin(samlCredential, userIdentifierAttr);
} }
log.info("User ID: {}, User identifier: {}, User name: {}, service ID: {}, service name: {}", log.info("{} - user_id '{}', user_identifier '{}', user_name '{}', service_identifier '{}', service_name: '{}'",
id, identifier, name, clientId, clientName); getFilterName(), id, identifier, name, clientId, clientName);
return true; return true;
} }

View File

@ -5,11 +5,12 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import cz.muni.ics.oauth2.model.ClientDetailsEntity; import cz.muni.ics.oauth2.model.ClientDetailsEntity;
import cz.muni.ics.oidc.BeanUtil; import cz.muni.ics.oidc.BeanUtil;
import cz.muni.ics.oidc.exceptions.ConfigurationException;
import cz.muni.ics.oidc.saml.SamlProperties; import cz.muni.ics.oidc.saml.SamlProperties;
import cz.muni.ics.oidc.server.filters.FilterParams; import cz.muni.ics.oidc.server.filters.AuthProcFilterCommonVars;
import cz.muni.ics.oidc.server.filters.FiltersUtils; import cz.muni.ics.oidc.server.filters.FiltersUtils;
import cz.muni.ics.oidc.server.filters.AuthProcFilter; import cz.muni.ics.oidc.server.filters.AuthProcFilter;
import cz.muni.ics.oidc.server.filters.AuthProcFilterParams; import cz.muni.ics.oidc.server.filters.AuthProcFilterInitContext;
import java.sql.Connection; import java.sql.Connection;
import java.sql.Date; import java.sql.Date;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
@ -29,6 +30,7 @@ import org.springframework.util.StringUtils;
* Filter for collecting data about login. * Filter for collecting data about login.
* *
* Configuration (replace [name] part with the name defined for the filter): * Configuration (replace [name] part with the name defined for the filter):
* @see cz.muni.ics.oidc.server.filters.AuthProcFilter (basic configuration options)
* <ul> * <ul>
* <li><b>filter.[name].idpNameAttributeName</b> - Mapping to Request attribute containing name of used * <li><b>filter.[name].idpNameAttributeName</b> - Mapping to Request attribute containing name of used
* Identity Provider</li> * Identity Provider</li>
@ -51,8 +53,6 @@ import org.springframework.util.StringUtils;
@Slf4j @Slf4j
public class ProxyStatisticsFilter extends AuthProcFilter { public class ProxyStatisticsFilter extends AuthProcFilter {
public static final String APPLIED = "APPLIED_" + ProxyStatisticsFilter.class.getSimpleName();
/* CONFIGURATION OPTIONS */ /* CONFIGURATION OPTIONS */
private static final String IDP_NAME_ATTRIBUTE_NAME = "idpNameAttributeName"; private static final String IDP_NAME_ATTRIBUTE_NAME = "idpNameAttributeName";
private static final String IDP_ENTITY_ID_ATTRIBUTE_NAME = "idpEntityIdAttributeName"; private static final String IDP_ENTITY_ID_ATTRIBUTE_NAME = "idpEntityIdAttributeName";
@ -74,62 +74,55 @@ public class ProxyStatisticsFilter extends AuthProcFilter {
/* END OF CONFIGURATION OPTIONS */ /* END OF CONFIGURATION OPTIONS */
private final DataSource mitreIdStats; private final DataSource mitreIdStats;
private final String filterName;
private final SamlProperties samlProperties; private final SamlProperties samlProperties;
public ProxyStatisticsFilter(AuthProcFilterParams params) { public ProxyStatisticsFilter(AuthProcFilterInitContext ctx) throws ConfigurationException {
super(params); super(ctx);
BeanUtil beanUtil = params.getBeanUtil(); BeanUtil beanUtil = ctx.getBeanUtil();
this.mitreIdStats = beanUtil.getBean("mitreIdStats", DataSource.class); this.mitreIdStats = beanUtil.getBean("mitreIdStats", DataSource.class);
this.samlProperties = beanUtil.getBean(SamlProperties.class); this.samlProperties = beanUtil.getBean(SamlProperties.class);
this.idpNameAttributeName = params.getProperty(IDP_NAME_ATTRIBUTE_NAME, this.idpNameAttributeName = FiltersUtils.fillStringPropertyOrDefaultVal(IDP_NAME_ATTRIBUTE_NAME, ctx,
"urn:cesnet:proxyidp:attribute:sourceIdPName"); "urn:cesnet:proxyidp:attribute:sourceIdPName");
this.idpEntityIdAttributeName = params.getProperty(IDP_ENTITY_ID_ATTRIBUTE_NAME, this.idpEntityIdAttributeName = FiltersUtils.fillStringPropertyOrDefaultVal(IDP_ENTITY_ID_ATTRIBUTE_NAME, ctx,
"urn:cesnet:proxyidp:attribute:sourceIdPEntityID"); "urn:cesnet:proxyidp:attribute:sourceIdPEntityID");
this.statisticsTableName = params.getProperty(STATISTICS_TABLE_NAME, "statistics_per_user"); this.statisticsTableName = FiltersUtils.fillStringPropertyOrDefaultVal(STATISTICS_TABLE_NAME, ctx, "statistics_per_user");
this.identityProvidersMapTableName = params.getProperty(IDENTITY_PROVIDERS_MAP_TABLE_NAME, "statistics_idp"); this.identityProvidersMapTableName = FiltersUtils.fillStringPropertyOrDefaultVal(IDENTITY_PROVIDERS_MAP_TABLE_NAME, ctx, "statistics_idp");
this.serviceProvidersMapTableName = params.getProperty(SERVICE_PROVIDERS_MAP_TABLE_NAME, "statistics_sp"); this.serviceProvidersMapTableName = FiltersUtils.fillStringPropertyOrDefaultVal(SERVICE_PROVIDERS_MAP_TABLE_NAME, ctx, "statistics_sp");
this.idpIdColumnName = params.getProperty(IDP_ID_COLUMN_NAME, "idpId"); this.idpIdColumnName = FiltersUtils.fillStringPropertyOrDefaultVal(IDP_ID_COLUMN_NAME, ctx, "idpId");
this.spIdColumnName = params.getProperty(SP_ID_COLUMN_NAME, "spId"); this.spIdColumnName = FiltersUtils.fillStringPropertyOrDefaultVal(SP_ID_COLUMN_NAME, ctx, "spId");
this.usernameColumnName = params.getProperty(USERNAME_COLUMN_NAME, "user"); this.usernameColumnName = FiltersUtils.fillStringPropertyOrDefaultVal(USERNAME_COLUMN_NAME, ctx, "user");
this.filterName = params.getFilterName();
} }
@Override @Override
protected String getSessionAppliedParamName() { protected boolean process(HttpServletRequest req, HttpServletResponse res, AuthProcFilterCommonVars params) {
return APPLIED;
}
@Override
protected boolean process(HttpServletRequest req, HttpServletResponse res, FilterParams params) {
ClientDetailsEntity client = params.getClient(); ClientDetailsEntity client = params.getClient();
if (client == null) { if (client == null) {
log.warn("{} - skip execution: no client provided", filterName); log.warn("{} - skip execution: no client provided", getFilterName());
return true; return true;
} else if (!StringUtils.hasText(client.getClientId())) { } else if (!StringUtils.hasText(client.getClientId())) {
log.warn("{} - skip execution: no client identifier provided", filterName); log.warn("{} - skip execution: no client identifier provided", getFilterName());
return true; return true;
} else if (!StringUtils.hasText(client.getClientName())) { } else if (!StringUtils.hasText(client.getClientName())) {
log.warn("{} - skip execution: no client name provided", filterName); log.warn("{} - skip execution: no client name provided", getFilterName());
return true; return true;
} }
SAMLCredential samlCredential = FiltersUtils.getSamlCredential(req); SAMLCredential samlCredential = FiltersUtils.getSamlCredential(req);
if (samlCredential == null) { if (samlCredential == null) {
log.warn("{} - skip execution: no authN object available, cannot extract user identifier and idp identifier", log.warn("{} - skip execution: no authN object available, cannot extract user identifier and idp identifier",
filterName); getFilterName());
return true; return true;
} }
String userIdentifier = FiltersUtils.getExtLogin(samlCredential, samlProperties.getUserIdentifierAttribute()); String userIdentifier = FiltersUtils.getExtLogin(samlCredential, samlProperties.getUserIdentifierAttribute());
if (!StringUtils.hasText(userIdentifier)) { if (!StringUtils.hasText(userIdentifier)) {
log.warn("{} - skip execution: no user identifier provided", filterName); log.warn("{} - skip execution: no user identifier provided", getFilterName());
return true; return true;
} else if (!StringUtils.hasText(samlCredential.getAttributeAsString(idpEntityIdAttributeName))) { } else if (!StringUtils.hasText(samlCredential.getAttributeAsString(idpEntityIdAttributeName))) {
log.warn("{} - skip execution: no authenticating idp identifier provided", filterName); log.warn("{} - skip execution: no authenticating idp identifier provided", getFilterName());
return true; return true;
} else if (!StringUtils.hasText(samlCredential.getAttributeAsString(idpNameAttributeName))) { } else if (!StringUtils.hasText(samlCredential.getAttributeAsString(idpNameAttributeName))) {
log.warn("{} - skip execution: no authenticating idp identifier provided", filterName); log.warn("{} - skip execution: no authenticating idp identifier provided", getFilterName());
return true; return true;
} }
@ -141,7 +134,7 @@ public class ProxyStatisticsFilter extends AuthProcFilter {
insertOrUpdateLogin(idpEntityId, idpName, clientId, clientName, userIdentifier); insertOrUpdateLogin(idpEntityId, idpName, clientId, clientName, userIdentifier);
log.info("{} - User identity: {}, service: {}, serviceName: {}, via IdP: {}", log.info("{} - User identity: {}, service: {}, serviceName: {}, via IdP: {}",
filterName, userIdentifier, client.getClientId(), client.getClientName(), idpEntityId); getFilterName(), userIdentifier, client.getClientId(), client.getClientName(), idpEntityId);
return true; return true;
} }
@ -158,12 +151,12 @@ public class ProxyStatisticsFilter extends AuthProcFilter {
if (spId == null) { if (spId == null) {
return; return;
} }
log.trace("{} - Extracted IDs for SP and IdP: spId={}({}), idpId={}({})", log.debug("{} - Extracted IDs for SP and IdP: spId={}({}), idpId={}({})",
filterName, spId, spIdentifier, idpId, idpEntityId); getFilterName(), spId, spIdentifier, idpId, idpEntityId);
insertOrUpdateLogin(c, idpId, spId, userId); insertOrUpdateLogin(c, idpId, spId, userId);
} catch (SQLException ex) { } catch (SQLException ex) {
log.warn("{} - caught SQLException", filterName); log.warn("{} - caught SQLException", getFilterName());
log.debug("{} - details:", filterName, ex); log.debug("{} - details:", getFilterName(), ex);
} }
} }
@ -174,6 +167,7 @@ public class ProxyStatisticsFilter extends AuthProcFilter {
} else { } else {
updateLogin(c, idpId, spId, userId); updateLogin(c, idpId, spId, userId);
} }
log.info("{} - login info stored in statistics", getFilterName());
} }
private boolean fetchLogin(Connection c, Long idpId, Long spId, String userId) { private boolean fetchLogin(Connection c, Long idpId, Long spId, String userId) {
@ -193,8 +187,8 @@ public class ProxyStatisticsFilter extends AuthProcFilter {
return rs.getInt("res") > 0; return rs.getInt("res") > 0;
} }
} catch (SQLException e) { } catch (SQLException e) {
log.warn("{} - caught SQLException when fetching login entry", filterName); log.warn("{} - caught SQLException when fetching login entry", getFilterName());
log.debug("{} - details:", filterName, e); log.debug("{} - details:", getFilterName(), e);
} }
return false; return false;
} }
@ -210,8 +204,8 @@ public class ProxyStatisticsFilter extends AuthProcFilter {
return rs.getLong(spIdColumnName); return rs.getLong(spIdColumnName);
} }
} catch (SQLException ex) { } catch (SQLException ex) {
log.warn("{} - caught SQLException when extracting SP ID", filterName); log.warn("{} - caught SQLException when extracting SP ID", getFilterName());
log.debug("{} - details:", filterName, ex); log.debug("{} - details:", getFilterName(), ex);
} }
return null; return null;
} }
@ -227,8 +221,8 @@ public class ProxyStatisticsFilter extends AuthProcFilter {
return rs.getLong(idpIdColumnName); return rs.getLong(idpIdColumnName);
} }
} catch (SQLException ex) { } catch (SQLException ex) {
log.warn("{} - caught SQLException when extracting IdP ID", filterName); log.warn("{} - caught SQLException when extracting IdP ID", getFilterName());
log.debug("{} - details:", filterName, ex); log.debug("{} - details:", getFilterName(), ex);
} }
return null; return null;
} }
@ -238,11 +232,11 @@ public class ProxyStatisticsFilter extends AuthProcFilter {
if (!Objects.equals(idpName, idpNameInDb)) { if (!Objects.equals(idpName, idpNameInDb)) {
if (idpNameInDb == null) { if (idpNameInDb == null) {
if (insertIdpMap(c, idpEntityId, idpName)) { if (insertIdpMap(c, idpEntityId, idpName)) {
log.trace("{} - IdP map entry inserted", filterName); log.debug("{} - IdP map entry inserted", getFilterName());
} }
} else { } else {
if (updateIdpMap(c, idpEntityId, idpName)) { if (updateIdpMap(c, idpEntityId, idpName)) {
log.trace("{} - IdP map entry updated", filterName); log.debug("{} - IdP map entry updated", getFilterName());
} }
} }
} }
@ -276,11 +270,11 @@ public class ProxyStatisticsFilter extends AuthProcFilter {
if (!Objects.equals(spName, spNameInDb)) { if (!Objects.equals(spName, spNameInDb)) {
if (spNameInDb == null) { if (spNameInDb == null) {
if (insertSpMap(c, spIdentifier, spName)) { if (insertSpMap(c, spIdentifier, spName)) {
log.trace("{} - SP map entry inserted", filterName); log.debug("{} - SP map entry inserted", getFilterName());
} }
} else { } else {
if (updateSpMap(c, spIdentifier, spName)) { if (updateSpMap(c, spIdentifier, spName)) {
log.trace("{} - SP map entry updated", filterName); log.debug("{} - SP map entry updated", getFilterName());
} }
} }
} }
@ -307,10 +301,10 @@ public class ProxyStatisticsFilter extends AuthProcFilter {
ps.setString(4, userId); ps.setString(4, userId);
ps.execute(); ps.execute();
log.debug("{} - Inserted first login for combination: idpId={}, spId={}, userId={}", log.debug("{} - Inserted first login for combination: idpId={}, spId={}, userId={}",
filterName, idpId, spId, userId); getFilterName(), idpId, spId, userId);
} catch (SQLException ex) { } catch (SQLException ex) {
log.warn("{} - caught SQLException when inserting login entry", filterName); log.warn("{} - caught SQLException when inserting login entry", getFilterName());
log.debug("{} - details:", filterName, ex); log.debug("{} - details:", getFilterName(), ex);
} }
} }
@ -329,10 +323,10 @@ public class ProxyStatisticsFilter extends AuthProcFilter {
ps.setString(4, userId); ps.setString(4, userId);
ps.execute(); ps.execute();
log.debug("{} - Updated login count by 1 for combination: idpId={}, spId={}, userId={}", log.debug("{} - Updated login count by 1 for combination: idpId={}, spId={}, userId={}",
filterName, idpId, spId, userId); getFilterName(), idpId, spId, userId);
} catch (SQLException ex) { } catch (SQLException ex) {
log.warn("{} - caught SQLException when updating login entry", filterName); log.warn("{} - caught SQLException when updating login entry", getFilterName());
log.debug("{} - details:", filterName, ex); log.debug("{} - details:", getFilterName(), ex);
} }
} }
@ -352,12 +346,12 @@ public class ProxyStatisticsFilter extends AuthProcFilter {
ps.setString(1, identifier); ps.setString(1, identifier);
ps.setString(2, name); ps.setString(2, name);
ps.execute(); ps.execute();
log.debug("{} - {} entry inserted", filterName, table); log.debug("{} - {} entry inserted", getFilterName(), table);
return true; return true;
} catch (SQLException ex) { } catch (SQLException ex) {
// someone has already inserted it // someone has already inserted it
log.trace("{} - {} entry failed to insert", filterName, table); log.debug("{} - {} entry failed to insert", getFilterName(), table);
log.trace("{} - details", filterName, ex); log.debug("{} - details", getFilterName(), ex);
} }
return false; return false;
} }
@ -377,11 +371,11 @@ public class ProxyStatisticsFilter extends AuthProcFilter {
ps.setString(1, name); ps.setString(1, name);
ps.setString(2, identifier); ps.setString(2, identifier);
ps.execute(); ps.execute();
log.debug("{} - {} entry updated", filterName, table); log.debug("{} - {} entry updated", getFilterName(), table);
return true; return true;
} catch (SQLException ex) { } catch (SQLException ex) {
log.trace("{} - {} map entry failed to update", filterName, table); log.debug("{} - {} map entry failed to update", getFilterName(), table);
log.trace("{} - details", filterName); log.debug("{} - details", getFilterName());
} }
return false; return false;
} }

View File

@ -1,19 +1,18 @@
package cz.muni.ics.oidc.server.filters.impl; package cz.muni.ics.oidc.server.filters.impl;
import cz.muni.ics.oidc.BeanUtil; import cz.muni.ics.oidc.exceptions.ConfigurationException;
import cz.muni.ics.oidc.models.Facility; import cz.muni.ics.oidc.models.Facility;
import cz.muni.ics.oidc.models.PerunAttributeValue; import cz.muni.ics.oidc.models.PerunAttributeValue;
import cz.muni.ics.oidc.models.PerunUser; import cz.muni.ics.oidc.models.PerunUser;
import cz.muni.ics.oidc.server.adapters.PerunAdapter; import cz.muni.ics.oidc.server.adapters.PerunAdapter;
import cz.muni.ics.oidc.server.configurations.FacilityAttrsConfig; import cz.muni.ics.oidc.server.configurations.FacilityAttrsConfig;
import cz.muni.ics.oidc.server.configurations.PerunOidcConfig; import cz.muni.ics.oidc.server.configurations.PerunOidcConfig;
import cz.muni.ics.oidc.server.filters.FilterParams;
import cz.muni.ics.oidc.server.filters.FiltersUtils;
import cz.muni.ics.oidc.server.filters.AuthProcFilter; import cz.muni.ics.oidc.server.filters.AuthProcFilter;
import cz.muni.ics.oidc.server.filters.AuthProcFilterParams; import cz.muni.ics.oidc.server.filters.AuthProcFilterCommonVars;
import cz.muni.ics.oidc.server.filters.AuthProcFilterInitContext;
import cz.muni.ics.oidc.server.filters.FiltersUtils;
import cz.muni.ics.oidc.web.controllers.PerunUnapprovedController; import cz.muni.ics.oidc.web.controllers.PerunUnapprovedController;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
@ -27,6 +26,7 @@ import org.springframework.util.StringUtils;
* the environment the service is in. * the environment the service is in.
* *
* Configuration (replace [name] part with the name defined for the filter): * Configuration (replace [name] part with the name defined for the filter):
* @see cz.muni.ics.oidc.server.filters.AuthProcFilter (basic configuration options)
* <ul> * <ul>
* <li><b>filter.[name].allEnvGroups</b> - Comma separated list of GROUP IDs the user must be always member of</li> * <li><b>filter.[name].allEnvGroups</b> - Comma separated list of GROUP IDs the user must be always member of</li>
* <li><b>filter.[name].allEnvGroups</b> - Comma separated list of VO IDs the user must be always member of</li> * <li><b>filter.[name].allEnvGroups</b> - Comma separated list of VO IDs the user must be always member of</li>
@ -46,8 +46,6 @@ import org.springframework.util.StringUtils;
@Slf4j @Slf4j
public class ValidUserFilter extends AuthProcFilter { public class ValidUserFilter extends AuthProcFilter {
public static final String APPLIED = "APPLIED_" + ValidUserFilter.class.getSimpleName();
/* CONFIGURATION OPTIONS */ /* CONFIGURATION OPTIONS */
private static final String ALL_ENV_GROUPS = "allEnvGroups"; private static final String ALL_ENV_GROUPS = "allEnvGroups";
private static final String ALL_ENV_VOS = "allEnvVos"; private static final String ALL_ENV_VOS = "allEnvVos";
@ -66,85 +64,92 @@ public class ValidUserFilter extends AuthProcFilter {
private final PerunAdapter perunAdapter; private final PerunAdapter perunAdapter;
private final FacilityAttrsConfig facilityAttrsConfig; private final FacilityAttrsConfig facilityAttrsConfig;
private final String filterName;
private final PerunOidcConfig config; private final PerunOidcConfig config;
public ValidUserFilter(AuthProcFilterParams params) { public ValidUserFilter(AuthProcFilterInitContext ctx) throws ConfigurationException {
super(params); super(ctx);
BeanUtil beanUtil = params.getBeanUtil(); this.perunAdapter = ctx.getPerunAdapterBean();
this.perunAdapter = beanUtil.getBean(PerunAdapter.class); this.config = ctx.getPerunOidcConfigBean();
this.facilityAttrsConfig = beanUtil.getBean(FacilityAttrsConfig.class); this.facilityAttrsConfig = ctx.getBeanUtil().getBean(FacilityAttrsConfig.class);
this.allEnvGroups = this.getIdsFromParam(params, ALL_ENV_GROUPS); this.allEnvGroups = getIdsFromParam(ctx, ALL_ENV_GROUPS);
this.allEnvVos = this.getIdsFromParam(params, ALL_ENV_VOS); this.allEnvVos = getIdsFromParam(ctx, ALL_ENV_VOS);
this.testEnvGroups = this.getIdsFromParam(params, TEST_ENV_GROUPS); this.testEnvGroups = getIdsFromParam(ctx, TEST_ENV_GROUPS);
this.testEnvVos = this.getIdsFromParam(params, TEST_ENV_VOS); this.testEnvVos = getIdsFromParam(ctx, TEST_ENV_VOS);
this.prodEnvGroups = this.getIdsFromParam(params, PROD_ENV_GROUPS); this.prodEnvGroups = getIdsFromParam(ctx, PROD_ENV_GROUPS);
this.prodEnvVos = this.getIdsFromParam(params, PROD_ENV_VOS); this.prodEnvVos = getIdsFromParam(ctx, PROD_ENV_VOS);
this.filterName = params.getFilterName();
this.config = beanUtil.getBean(PerunOidcConfig.class); if (allSetsEmpty()) {
throw new ConfigurationException("All sets are configured to be empty");
}
}
private boolean allSetsEmpty() {
return allEnvVos.isEmpty() && allEnvGroups.isEmpty()
&& prodEnvVos.isEmpty() && prodEnvGroups.isEmpty()
&& testEnvVos.isEmpty() && testEnvGroups.isEmpty();
} }
@Override @Override
protected String getSessionAppliedParamName() { protected boolean process(HttpServletRequest req, HttpServletResponse res, AuthProcFilterCommonVars params) {
return APPLIED;
}
@Override
protected boolean process(HttpServletRequest req, HttpServletResponse res, FilterParams params) {
Set<Long> additionalVos = new HashSet<>();
Set<Long> additionalGroups = new HashSet<>();
PerunUser user = params.getUser(); PerunUser user = params.getUser();
if (user == null || user.getId() == null) { if (user == null || user.getId() == null) {
log.debug("{} - skip filter execution: no user provided", filterName); log.debug("{} - skip filter execution: no user provided", getFilterName());
return true; return true;
} }
Facility facility = params.getFacility(); Facility facility = params.getFacility();
if (facility == null || facility.getId() == null) { if (facility == null || facility.getId() == null) {
log.debug("{} - skip filter execution: no facility provided", filterName); log.debug("{} - skip filter execution: no facility provided", getFilterName());
return true; return true;
} }
if (!checkMemberValidInGroupsAndVos(user, facility, res, params, allEnvVos, allEnvGroups, if (!checkMemberValidInGroupsAndVos(user, allEnvVos, allEnvGroups)) {
PerunUnapprovedController.UNAPPROVED_NOT_IN_MANDATORY_VOS_GROUPS)) { redirectCannotAccess(res, facility, user, params.getClientIdentifier(), PerunUnapprovedController.UNAPPROVED_NOT_IN_MANDATORY_VOS_GROUPS);
return false; return false;
} }
PerunAttributeValue isTestSp = perunAdapter.getFacilityAttributeValue(facility.getId(), facilityAttrsConfig.getTestSpAttr()); PerunAttributeValue isTestSpAttrValue = perunAdapter.getFacilityAttributeValue(facility.getId(), facilityAttrsConfig.getTestSpAttr());
boolean isTestSpBool = false; boolean testService = false;
if (isTestSp != null) { if (isTestSpAttrValue != null) {
isTestSpBool = isTestSp.valueAsBoolean(); testService = isTestSpAttrValue.valueAsBoolean();
} }
log.debug("{} - service {} in test env", filterName, (isTestSpBool ? "is" : "is not"));
if (isTestSpBool) {
additionalVos.addAll(testEnvVos);
additionalGroups.addAll(testEnvGroups);
if (!checkMemberValidInGroupsAndVos(user, facility, res, params, additionalVos, log.debug("{} - service {} in test env", getFilterName(), (testService ? "is" : "is not"));
additionalGroups, PerunUnapprovedController.UNAPPROVED_NOT_IN_TEST_VOS_GROUPS)) {
return false; Set<Long> vos = new HashSet<>();
} Set<Long> groups = new HashSet<>();
String unapprovedMapping;
if (testService) {
vos.addAll(testEnvVos);
groups.addAll(testEnvGroups);
unapprovedMapping = PerunUnapprovedController.UNAPPROVED_NOT_IN_TEST_VOS_GROUPS;
} else { } else {
additionalVos.addAll(prodEnvVos); vos.addAll(prodEnvVos);
additionalGroups.addAll(prodEnvGroups); groups.addAll(prodEnvGroups);
unapprovedMapping = PerunUnapprovedController.UNAPPROVED_NOT_IN_PROD_VOS_GROUPS;
if (!checkMemberValidInGroupsAndVos(user, facility, res, params, additionalVos, }
additionalGroups, PerunUnapprovedController.UNAPPROVED_NOT_IN_PROD_VOS_GROUPS)) { if (!checkMemberValidInGroupsAndVos(user, vos, groups)) {
return false; log.info("{} - Redirecting to unapproved page with mapping '{}'", getFilterName(), unapprovedMapping);
} redirectCannotAccess(res, facility, user, params.getClientIdentifier(), unapprovedMapping);
return false;
} }
log.info("{} - user satisfies the membership criteria", filterName); log.info("{} - user satisfies the membership criteria", getFilterName());
return true; return true;
} }
private Set<Long> getIdsFromParam(AuthProcFilterParams params, String propKey) { private void redirectCannotAccess(HttpServletResponse res, Facility facility, PerunUser user,
String clientId, String mapping)
{
FiltersUtils.redirectUserCannotAccess(config.getConfigBean().getIssuer(), res, facility, user,
clientId, facilityAttrsConfig, perunAdapter, mapping);
}
private Set<Long> getIdsFromParam(AuthProcFilterInitContext params, String propKey) {
Set<Long> result = new HashSet<>(); Set<Long> result = new HashSet<>();
String prop = params.getProperty(propKey); String prop = params.getProperty(propKey, "");
if (StringUtils.hasText(prop)) { if (StringUtils.hasText(prop)) {
String[] parts = prop.split(","); String[] parts = prop.split(",");
for (String idStr: parts) { for (String idStr: parts) {
@ -155,26 +160,11 @@ public class ValidUserFilter extends AuthProcFilter {
return result; return result;
} }
private boolean checkMemberValidInGroupsAndVos( private boolean checkMemberValidInGroupsAndVos(PerunUser user, Set<Long> vos, Set<Long> groups) {
PerunUser user,
Facility facility,
HttpServletResponse response,
FilterParams params,
Set<Long> vos,
Set<Long> groups,
String redirectUrl
) {
if (!perunAdapter.isValidMemberInGroupsAndVos(user.getId(), vos, groups)) { if (!perunAdapter.isValidMemberInGroupsAndVos(user.getId(), vos, groups)) {
log.info("{} - user is not member in required set of vos and groups", filterName); log.info("{} - user is not member in required set of vos and groups", getFilterName());
log.debug("{} - user: '{}', vos: '{}', groups: '{}'", log.debug("{} - user: '{}', vos: '{}', groups: '{}'",
filterName, user.getId(), vos, groups); getFilterName(), user.getId(), vos, groups);
Map<String, PerunAttributeValue> facilityAttributes = perunAdapter.getFacilityAttributeValues(
facility, facilityAttrsConfig.getMembershipAttrNames());
FiltersUtils.redirectUserCannotAccess(config.getConfigBean().getIssuer(), response, facility, user,
params.getClientIdentifier(), facilityAttrsConfig, facilityAttributes, perunAdapter, redirectUrl);
return false; return false;
} }
return true; return true;

View File

@ -1,43 +0,0 @@
package cz.muni.ics.oidc.server.filters.impl.mdc;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.MDC;
public class RemoteAddressMDCFilter {
private static final String[] IP_HEADER_CANDIDATES = {
"X-Forwarded-For",
"Proxy-Client-IP",
"WL-Proxy-Client-IP",
"HTTP_X_FORWARDED_FOR",
"HTTP_X_FORWARDED",
"HTTP_X_CLUSTER_CLIENT_IP",
"HTTP_CLIENT_IP",
"HTTP_FORWARDED_FOR",
"HTTP_FORWARDED",
"HTTP_VIA",
"REMOTE_ADDR"
};
private static final String REMOTE_ADDR = "remoteAddr";
public void doFilter(ServletRequest servletRequest) {
MDC.put(REMOTE_ADDR, getRemoteAddr((HttpServletRequest) servletRequest));
}
private String getRemoteAddr(HttpServletRequest request) {
if (request.getRemoteAddr() != null) {
return request.getRemoteAddr();
}
for (String header: IP_HEADER_CANDIDATES) {
String ipList = request.getHeader(header);
if (ipList != null && ipList.length() != 0 && !"unknown".equalsIgnoreCase(ipList)) {
return ipList.split(",")[0];
}
}
return "-";
}
}

View File

@ -1,23 +0,0 @@
package cz.muni.ics.oidc.server.filters.impl.mdc;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.MDC;
public class SessionIdMDCFilter {
private static final int SIZE = 12;
private static final String SESSION_ID = "sessionID";
public void doFilter(ServletRequest servletRequest) {
HttpServletRequest req = (HttpServletRequest) servletRequest;
if (req.getSession() != null) {
String id = req.getSession().getId();
if (id != null && id.length() > SIZE) {
id = id.substring(0, SIZE);
}
MDC.put(SESSION_ID, id);
}
}
}

View File

@ -36,7 +36,7 @@ public class AupController {
public static final String URL = "aup"; public static final String URL = "aup";
public static final String NEW_AUPS = "newAups"; public static final String NEW_AUPS = "newAups";
public static final String APPROVED = "approved"; public static final String APPROVED = "aup_approved";
public static final String RETURN_URL = "returnUrl"; public static final String RETURN_URL = "returnUrl";
public static final String USER_ATTR = "userAttr"; public static final String USER_ATTR = "userAttr";

View File

@ -1,7 +1,7 @@
package cz.muni.ics.oidc.web.controllers; package cz.muni.ics.oidc.web.controllers;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_ACCEPTED; import static cz.muni.ics.oidc.server.filters.AuthProcFilterConstants.PARAM_ACCEPTED;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_TARGET; import static cz.muni.ics.oidc.server.filters.AuthProcFilterConstants.PARAM_TARGET;
import cz.muni.ics.oidc.server.configurations.PerunOidcConfig; import cz.muni.ics.oidc.server.configurations.PerunOidcConfig;
import cz.muni.ics.oidc.web.WebHtmlClasses; import cz.muni.ics.oidc.web.WebHtmlClasses;

View File

@ -1,10 +1,10 @@
package cz.muni.ics.oidc.web.controllers; package cz.muni.ics.oidc.web.controllers;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_CLIENT_ID; import static cz.muni.ics.oidc.server.filters.AuthProcFilterConstants.PARAM_CLIENT_ID;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_HEADER; import static cz.muni.ics.oidc.server.filters.AuthProcFilterConstants.PARAM_HEADER;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_MESSAGE; import static cz.muni.ics.oidc.server.filters.AuthProcFilterConstants.PARAM_MESSAGE;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_REASON; import static cz.muni.ics.oidc.server.filters.AuthProcFilterConstants.PARAM_REASON;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_TARGET; import static cz.muni.ics.oidc.server.filters.AuthProcFilterConstants.PARAM_TARGET;
import cz.muni.ics.oauth2.model.ClientDetailsEntity; import cz.muni.ics.oauth2.model.ClientDetailsEntity;
import cz.muni.ics.oauth2.service.ClientDetailsEntityService; import cz.muni.ics.oauth2.service.ClientDetailsEntityService;
@ -12,8 +12,6 @@ import cz.muni.ics.oidc.server.configurations.PerunOidcConfig;
import cz.muni.ics.oidc.web.WebHtmlClasses; import cz.muni.ics.oidc.web.WebHtmlClasses;
import cz.muni.ics.openid.connect.view.HttpCodeView; import cz.muni.ics.openid.connect.view.HttpCodeView;
import java.util.Map; import java.util.Map;
import java.util.Properties;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;

View File

@ -16,9 +16,9 @@
package cz.muni.ics.openid.connect.web.endpoint; package cz.muni.ics.openid.connect.web.endpoint;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_POST_LOGOUT_REDIRECT_URI; import static cz.muni.ics.oidc.server.filters.AuthProcFilterConstants.PARAM_POST_LOGOUT_REDIRECT_URI;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_STATE; import static cz.muni.ics.oidc.server.filters.AuthProcFilterConstants.PARAM_STATE;
import static cz.muni.ics.oidc.server.filters.PerunFilterConstants.PARAM_TARGET; import static cz.muni.ics.oidc.server.filters.AuthProcFilterConstants.PARAM_TARGET;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;