summaryrefslogtreecommitdiff
path: root/src/main/java/at/gv/util/filter
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/at/gv/util/filter')
-rw-r--r--src/main/java/at/gv/util/filter/moaid/AbstractGenericMOAIDAuthenticationServlet.java246
-rw-r--r--src/main/java/at/gv/util/filter/moaid/MOAIDAuthenticationFilter.java259
2 files changed, 505 insertions, 0 deletions
diff --git a/src/main/java/at/gv/util/filter/moaid/AbstractGenericMOAIDAuthenticationServlet.java b/src/main/java/at/gv/util/filter/moaid/AbstractGenericMOAIDAuthenticationServlet.java
new file mode 100644
index 0000000..f9edb35
--- /dev/null
+++ b/src/main/java/at/gv/util/filter/moaid/AbstractGenericMOAIDAuthenticationServlet.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright 2011 Federal Chancellery Austria and
+ * Graz University of Technology
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package at.gv.util.filter.moaid;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.time.DateFormatUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import at.gv.util.MiscUtil;
+import at.gv.util.ToStringUtil;
+import at.gv.util.WebAppUtil;
+import at.gv.util.client.moaid.MOAIDClient;
+import at.gv.util.client.moaid.MOAIDClientException;
+import at.gv.util.config.EgovUtilConfiguration;
+import at.gv.util.xsd.saml.assertion.AssertionType;
+import at.gv.util.xsd.saml.protocol.ResponseType;
+
+/**
+ * @author <a href="mailto:arne.tauber@egiz.gv.at">Arne Tauber</a>
+ * @author <a href="mailto:thomas.knall@iaik.tugraz.at">Thomas Knall</a>
+ */
+public abstract class AbstractGenericMOAIDAuthenticationServlet extends HttpServlet {
+
+ private static final long serialVersionUID = 1L;
+ public static final String REQUEST_ATTRIBUTE_ERROR_MESSAGE = "javax.servlet.error.message";
+ //private boolean alreadyLogged = false;
+
+ private HttpServletRequest request = null;
+ private HttpServletResponse response = null;
+
+ private final Logger log = LoggerFactory.getLogger(AbstractGenericMOAIDAuthenticationServlet.class);
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ this.doPost(req, resp);
+ }
+
+ private void errorPage(HttpServletRequest request, HttpServletResponse response, String... args) {
+ this.request = request;
+ this.response = response;
+ log.debug("Forwarding to error page \"" + this.getErrorPage() + "\".");
+ log.error("Messages for Errorpage (saved in request attribute \"" + REQUEST_ATTRIBUTE_ERROR_MESSAGE + "\"): " + ToStringUtil.toString(args));
+ request.setAttribute(REQUEST_ATTRIBUTE_ERROR_MESSAGE, ToStringUtil.toString(args));
+ try {
+ request.getRequestDispatcher(this.getErrorPage()).forward(request, response);
+ return;
+ } catch (Throwable t) {
+ log.error("Unexpected error (" + t.getMessage() + ") forwarding to error page \"" + this.getErrorPage() + "\".");
+ }
+ }
+
+ @Override
+ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ log.debug("MOAIDLogin invoked.");
+
+ this.request = request;
+ this.response = response;
+
+ String artifact = request.getParameter("SAMLArtifact");
+ if (MiscUtil.isEmpty(artifact)) {
+ this.errorPage(request, response, "SAMLArtifact post parameter must not be null or empty.");
+ return;
+ }
+
+ String expectedTarget = this.getExpectedTarget();
+ String target = request.getParameter("Target");
+ if (MiscUtil.isNotEmpty(target)) {
+ if (MiscUtil.isNotEmpty(expectedTarget)) {
+ log.debug("Verifying target parameter.");
+ if (!expectedTarget.equals(target)) {
+ this.errorPage(request, response, "Transmitted target parameter does not match the expected target parameter value \"" + expectedTarget + "\".");
+ return;
+ }
+ }
+ } else {
+ log.debug("No expected target parameter given. Maybe configured as wbpk application. Skipping target value evaluation.");
+ }
+
+ log.debug("SAMLArtifact = \"" + artifact + "\".");
+
+ AssertionType assertion = null;
+ try {
+ MOAIDClient client = new MOAIDClient(this.getConfiguration());
+ ResponseType moaidResponse = client.sendGetAuthenticationDataRequest(this.getAuthDataURL(), artifact);
+ if (!"Success".equals(moaidResponse.getStatus().getStatusCode().getValue().getLocalPart())) {
+ throw new MOAIDClientException("Wrong MOA-ID return code: " + moaidResponse.getStatus().getStatusCode().getValue().toString());
+ }
+ assertion = moaidResponse.getAssertion().get(0);
+ } catch (MOAIDClientException c) {
+ String em = "Error retrieving authentication data (" + c.getMessage() + ").";
+ log.error(em);
+ this.errorPage(request, response, em);
+ return;
+ }
+
+ HttpSession session = request.getSession(false);
+
+ if (session != null) {
+
+ HashMap<String, Object> attributes = new HashMap<String,Object>();
+
+ Enumeration<String> enames = session.getAttributeNames();
+ while (enames.hasMoreElements()) {
+ String name = enames.nextElement();
+ if (!name.equals("JSESSIONID"))
+ attributes.put(name, session.getAttribute( name));
+ }
+
+// // alle Notizen kopieren
+// HashMap<String, Object> notes = new HashMap<String,Object>();
+// Iterator<String> nameit = session.getNoteN;
+// while (nameit.hasNext()) {
+// String name = nameit.next();
+// notes.put( name, session.getNote( name));
+// }
+//
+ session.invalidate();
+
+
+ session = request.getSession(true);
+ // Attribute und Notizen zurückkopieren
+ for (Entry<String,Object> et : attributes.entrySet()) {
+ session.setAttribute( et.getKey(), et.getValue());
+ }
+
+ } else
+ session = request.getSession(true);
+
+
+ log.debug("Using session " + session.getId() + ", created at " + DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.format(session.getCreationTime()) + ".");
+ Object authData = this.getAuthDataObject(assertion, request);
+
+ if (authData == null) {
+ log.info("No auth data provided from implementing application. Denying access.");
+ response.sendError(HttpServletResponse.SC_FORBIDDEN, "Access is denied.");
+ return;
+ }
+
+ log.debug("Authentication data = " + authData);
+
+ session.setAttribute(this.getAuthDataSessionAttribute(), authData);
+
+
+
+ String originalURL = null;
+ String authenticatedPage = StringUtils.trim(this.getAuthenticatedPage(request, originalURL));
+ if (MiscUtil.isNotEmpty(authenticatedPage)) {
+ try {
+ // check if absolute URL is given
+ new URL(authenticatedPage);
+ // if absolute URL is given take it
+ } catch (MalformedURLException e) {
+ // if no absolute URL is given, prepend the webapp context
+ authenticatedPage = WebAppUtil.getBaseURL(request) + MiscUtil.removePrecedingSlash(authenticatedPage);
+ }
+ log.debug("User is authenticated. Authenticated page given. Redirecting to \"" + authenticatedPage + "\".");
+ response.sendRedirect(response.encodeRedirectURL(authenticatedPage));
+ return;
+ } else {
+ log.debug("No authenticated page given. Trying to find original url.");
+ String sessionAttribute = this.getStoredRequestURLSessionAttribute();
+ if (MiscUtil.isNotEmpty(sessionAttribute)) {
+ log.debug("Fetching saved request url from session attribute \"" + sessionAttribute + "\".");
+ originalURL = (String) session.getAttribute(sessionAttribute);
+ session.removeAttribute(sessionAttribute);
+ }
+ if (originalURL == null) {
+ log.warn("Unable to find saved request. Session seems to got lost.");
+ String sessionLostPage = this.getSessionLostPage();
+ if (MiscUtil.isNotEmpty(sessionLostPage)) {
+ sessionLostPage = WebAppUtil.getBaseURL(request) + MiscUtil.removePrecedingSlash(sessionLostPage);
+ log.debug("Found failsafe page for redirection in case of session loss. Redirecting to \"" + sessionLostPage + "\".");
+ response.sendRedirect(response.encodeRedirectURL(sessionLostPage));
+ return;
+ }
+ this.errorPage(request, response, "Unable to find saved request.");
+ return;
+ }
+ log.debug("User is authenticated. Redirecting to original location \"" + originalURL + "\".");
+ response.sendRedirect(response.encodeRedirectURL(originalURL));
+ return;
+ }
+ }
+
+ public HttpServletRequest getRequest() {
+ return request;
+ }
+
+ public HttpServletResponse getResponse() {
+ return response;
+ }
+
+ public abstract String getAuthenticatedPage(HttpServletRequest request, String savedRequestURL);
+
+ public abstract String getAuthDataSessionAttribute();
+
+ public abstract String getStoredRequestURLSessionAttribute();
+
+ public abstract String getErrorPage();
+
+ public abstract Object getAuthDataObject(AssertionType samlAssertion);
+
+ public Object getAuthDataObject(AssertionType samlAssertion, HttpServletRequest request) {
+ return this.getAuthDataObject(samlAssertion);
+ }
+
+ public abstract String getAuthDataURL();
+
+ public abstract String getSessionLostPage();
+
+ public abstract String getExpectedTarget();
+
+ public abstract EgovUtilConfiguration getConfiguration();
+
+
+
+}
diff --git a/src/main/java/at/gv/util/filter/moaid/MOAIDAuthenticationFilter.java b/src/main/java/at/gv/util/filter/moaid/MOAIDAuthenticationFilter.java
new file mode 100644
index 0000000..cb16b8f
--- /dev/null
+++ b/src/main/java/at/gv/util/filter/moaid/MOAIDAuthenticationFilter.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright 2011 Federal Chancellery Austria and
+ * Graz University of Technology
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package at.gv.util.filter.moaid;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+import java.util.regex.Pattern;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.apache.commons.lang.BooleanUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.time.DateFormatUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import at.gv.util.MiscUtil;
+import at.gv.util.ToStringUtil;
+import at.gv.util.WebAppUtil;
+
+/**
+ * @author <a href="mailto:arne.tauber@egiz.gv.at">Arne Tauber</a>
+ * @author <a href="mailto:thomas.knall@iaik.tugraz.at">Thomas Knall</a>
+ */
+public class MOAIDAuthenticationFilter implements Filter {
+
+ private final Logger log = LoggerFactory.getLogger(MOAIDAuthenticationFilter.class);
+
+ public static final String USER_AUTH_DATA_ID = "AnyAuthDataObject:authenticatedUser";
+ public static final String STORED_REQUEST_URL_ID = String.class.getName() + ":" + "storedRequestURL";
+
+ public static final String WEB_XML_INIT_PARAM_LOGIN_PAGE = "loginPage";
+ public static final String WEB_XML_INIT_PARAM_ENABLED = "enabled";
+ public static final String WEB_XML_INIT_PARAM_ERROR_PAGE = "errorPage";
+ public static final String WEB_XML_INIT_PARAM_AUTHENTICATED_PAGE = "authenticatedPage"; // optional
+ public static final String WEB_XML_INIT_PARAM_SESSION_LOST_PAGE = "sessionLostPage"; // optional
+ public static final String WEB_XML_INIT_PARAM_ALLOWED_LIST = "allowedList";
+ public static final String WEB_XML_INIT_PARAM_ALLOWED_REGEX = "allowed";
+
+ private static final String WEB_XML_INIT_PARAM_EXCLUDED_PAGES_DELIMITER = ",";
+
+ private boolean enabled = true;
+
+ private static String loginPage = null;
+ private boolean loginPageForward = true;
+ private static String errorPage = null;
+ private static String authenticatedPage = null;
+ private static String sessionLostPage = null;
+
+ private static String[] excludedPages = null;
+ private static Pattern excludedRegEx = null;
+
+ private HttpServletRequest servletRequest = null;
+
+ public void destroy() {
+ log.trace("Shutting down " + this.getClass().getName() + "...");
+ }
+
+ public static String getErrorPage() {
+ return errorPage;
+ }
+
+ public static String getAuthenticatedPage() {
+ return authenticatedPage;
+ }
+
+ public static String getLoginPage() {
+ return loginPage;
+ }
+
+ public static String getSessionLostPage() {
+ return sessionLostPage;
+ }
+
+ public HttpServletRequest getHttpServletRequest() {
+ return this.servletRequest;
+ }
+
+ private boolean isExcluded(String url) {
+ boolean excluded = false;
+ if (MiscUtil.isNotEmpty(excludedPages)) {
+ for (String candidate : excludedPages) {
+ if (StringUtils.upperCase(url).endsWith(StringUtils.upperCase(candidate))) {
+ excluded = true;
+ break;
+ }
+ }
+ }
+ if (excludedRegEx != null && !excluded) {
+ // log.debug("Trying to match regex \"{}\" with \"{}\".",
+ // excludedRegEx.toString(), url);
+ if (excludedRegEx.matcher(url).matches()) {
+ excluded = true;
+ }
+ }
+ log.debug("URL \"" + url + "\" is " + (excluded ? "" : "NOT ") + "excluded from filter.");
+ return excluded;
+ }
+
+ public void doFilter(ServletRequest request, ServletResponse response, final FilterChain filterChain) throws IOException, ServletException {
+ if (this.enabled) {
+ log.debug("Applying " + this.getClass().getSimpleName() + "...");
+
+ HttpServletRequest httpServletRequest = (HttpServletRequest) request;
+ servletRequest = httpServletRequest;
+ HttpServletResponse httpServletResponse = (HttpServletResponse) response;
+ HttpSession session = httpServletRequest.getSession();
+ log.debug("Using session " + session.getId() + ", created at " + DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.format(session.getCreationTime()) + ".");
+
+ Object anyObject = session.getAttribute(USER_AUTH_DATA_ID);
+ String requestURL = WebAppUtil.getRequestURLWithParameters(httpServletRequest, true);
+ log.trace("Request URL: " + requestURL);
+ if (anyObject == null && !this.isExcluded(requestURL)) {
+ Object dummyAuthData = this.provideDummyAuthenticationData();
+ if (dummyAuthData != null) {
+ log.warn("Unable to find regular authentication data but dummy authentication data is provided.");
+ log.debug("Authentication data = " + dummyAuthData.toString());
+ log.warn("Putting dummy authentication data into session.");
+ session.setAttribute(USER_AUTH_DATA_ID, dummyAuthData);
+ if (MiscUtil.isNotEmpty(getAuthenticatedPage())) {
+ if (loginPageForward) {
+ log.debug("Authenticated page is set. Forwarding to \"" + getAuthenticatedPage() + "\".");
+ RequestDispatcher dispatcher = request.getRequestDispatcher(getAuthenticatedPage());
+ dispatcher.forward(httpServletRequest, httpServletResponse);
+ } else {
+ log.debug("Authenticated page is set. Redirecting to \"" + getAuthenticatedPage() + "\".");
+ httpServletResponse.sendRedirect(httpServletResponse.encodeRedirectURL(getAuthenticatedPage()));
+ }
+ return;
+ }
+ } else {
+ if (MiscUtil.isNotEmpty(getAuthenticatedPage())) {
+ log.debug("Unable to find authentication data. Authenticated page is given so there is no need to save original request url. " + (loginPageForward ? "Forwarding" : "Redirecting") + " to login page \"" + loginPage + "\".");
+ } else {
+ log.debug("Unable to find authentication data. Storing request url and " + (loginPageForward ? "forwarding" : "redirecting") + " to login page \"" + loginPage + "\".");
+ // TODO: save HttpServletRequest
+ // log.debug("new CustomHttpServletRequest(request).toString() =
+ // {}", new
+ // CustomHttpServletRequest(httpServletRequest).toString());
+ session.setAttribute(STORED_REQUEST_URL_ID, requestURL);
+ }
+ if (loginPageForward) {
+ RequestDispatcher dispatcher = request.getRequestDispatcher(loginPage);
+ dispatcher.forward(httpServletRequest, httpServletResponse);
+ } else {
+ httpServletResponse.sendRedirect(httpServletResponse.encodeRedirectURL(loginPage));
+ }
+ return;
+ }
+
+ }
+ }
+
+ filterChain.doFilter(request, response);
+ }
+
+ public void init(FilterConfig filterConfig) throws ServletException {
+ log.debug("Starting init of " + this.getClass().getName() + ".");
+
+ // enabled?
+ String enabledValue = StringUtils.trimToNull(filterConfig.getInitParameter(WEB_XML_INIT_PARAM_ENABLED));
+ this.enabled = BooleanUtils.isNotFalse(BooleanUtils.toBooleanObject(enabledValue));
+
+ // login page
+ loginPage = StringUtils.trim(filterConfig.getInitParameter(WEB_XML_INIT_PARAM_LOGIN_PAGE));
+ if (MiscUtil.isEmpty(loginPage)) {
+ throw new ServletException("ServletInitParameter \"" + WEB_XML_INIT_PARAM_LOGIN_PAGE + "\" must not be empty.");
+ }
+ loginPageForward = false; //!WebAppUtil.isFullQualifiedURL(loginPage);
+
+ // error page
+ errorPage = StringUtils.trim(filterConfig.getInitParameter(WEB_XML_INIT_PARAM_ERROR_PAGE));
+ if (MiscUtil.isEmpty(errorPage)) {
+ throw new ServletException("ServletInitParameter \"" + WEB_XML_INIT_PARAM_ERROR_PAGE + "\" must not be empty.");
+ }
+
+ // session lost page
+ sessionLostPage = StringUtils.trim(filterConfig.getInitParameter(WEB_XML_INIT_PARAM_SESSION_LOST_PAGE));
+ if (MiscUtil.isEmpty(sessionLostPage)) {
+ log.warn("ServletInitParameter \"" + WEB_XML_INIT_PARAM_SESSION_LOST_PAGE
+ + "\" is empty. This parameter defines a failsafe url the browser is redirected to if the original url has been lost due to session timeout.");
+ }
+
+ // authenticated page
+ authenticatedPage = StringUtils.trim(filterConfig.getInitParameter(WEB_XML_INIT_PARAM_AUTHENTICATED_PAGE));
+ if (MiscUtil.isEmpty(authenticatedPage)) {
+ log.debug("ServletInitParameter \"" + WEB_XML_INIT_PARAM_AUTHENTICATED_PAGE
+ + "\" is empty. This parameter defines the url the user is redirected to (instead of the original url) on successful authentication.");
+ }
+ String excluded = filterConfig.getInitParameter(WEB_XML_INIT_PARAM_ALLOWED_LIST);
+ ArrayList<String> excludedList = new ArrayList<String>();
+ if (MiscUtil.isNotEmpty(excluded)) {
+ StringTokenizer tokenizer = new StringTokenizer(excluded, WEB_XML_INIT_PARAM_EXCLUDED_PAGES_DELIMITER);
+ while (tokenizer.hasMoreTokens()) {
+ String ex = StringUtils.trim(tokenizer.nextToken());
+ if (MiscUtil.isNotEmpty(ex)) {
+ excludedList.add(ex);
+ }
+ }
+ }
+ excludedList.add(loginPage);
+ excludedList.add(errorPage);
+ excludedPages = new String[excludedList.size()];
+ excludedPages = excludedList.toArray(excludedPages);
+
+ String excludedRegExString = StringUtils.trim(filterConfig.getInitParameter(WEB_XML_INIT_PARAM_ALLOWED_REGEX));
+ if (MiscUtil.isNotEmpty(excludedRegExString)) {
+ excludedRegEx = Pattern.compile(excludedRegExString);
+ }
+
+ if (!this.enabled) {
+ log.info(this.getClass().getName() + " is DISABLED");
+ } else {
+ log.debug(WEB_XML_INIT_PARAM_ENABLED + " = \"" + this.enabled + "\"");
+ }
+ log.debug(WEB_XML_INIT_PARAM_LOGIN_PAGE + " [" + (loginPageForward ? "forward" : "redirect") + "] = \"" + loginPage + "\"");
+ log.debug(WEB_XML_INIT_PARAM_AUTHENTICATED_PAGE + " = \"" + (MiscUtil.isNotEmpty(authenticatedPage) ? authenticatedPage : "<n/a>") + "\"");
+ log.debug(WEB_XML_INIT_PARAM_ERROR_PAGE + " = \"" + errorPage + "\"");
+ log.debug(WEB_XML_INIT_PARAM_SESSION_LOST_PAGE + " = \"" + (MiscUtil.isNotEmpty(sessionLostPage) ? sessionLostPage : "<n/a>") + "\"");
+ log.debug(WEB_XML_INIT_PARAM_ALLOWED_LIST + " = " + ToStringUtil.toString(excludedPages, ", ", "\""));
+ log.debug(WEB_XML_INIT_PARAM_ALLOWED_REGEX + " = \"" + (excludedRegEx != null ? excludedRegEx.pattern() : "<n/a>") + "\"");
+ }
+
+ /**
+ * May be overwritten in order to provide static authentication data during
+ * development process.
+ *
+ * @return some kind of dummy authentication data
+ */
+ public Object provideDummyAuthenticationData() {
+ return null;
+ }
+
+}