This is an automated email from the ASF dual-hosted git repository. radcortez pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/tomee.git
commit c5c8a3e78ffd64edbd721223cc250b46fd6e1b6f Author: Roberto Cortez <[email protected]> AuthorDate: Fri Dec 28 13:10:59 2018 +0000 TOMEE-2365 - Perform authentication on the second step of the form. --- .../security/cdi/LoginToContinueInterceptor.java | 41 ++++- .../security/http/LoginToContinueMechanism.java | 48 +++++- .../tomee/security/http/SavedAuthentication.java | 41 +++++ .../apache/tomee/security/http/SavedRequest.java | 178 +++++++++++++++++++++ .../security/http/TomEEHttpMessageContext.java | 12 +- 5 files changed, 311 insertions(+), 9 deletions(-) diff --git a/tomee/tomee-security/src/main/java/org/apache/tomee/security/cdi/LoginToContinueInterceptor.java b/tomee/tomee-security/src/main/java/org/apache/tomee/security/cdi/LoginToContinueInterceptor.java index 1895689..1e0b0f3 100644 --- a/tomee/tomee-security/src/main/java/org/apache/tomee/security/cdi/LoginToContinueInterceptor.java +++ b/tomee/tomee-security/src/main/java/org/apache/tomee/security/cdi/LoginToContinueInterceptor.java @@ -17,6 +17,7 @@ package org.apache.tomee.security.cdi; import org.apache.tomee.security.http.LoginToContinueMechanism; +import org.apache.tomee.security.http.SavedRequest; import javax.annotation.Priority; import javax.interceptor.AroundInvoke; @@ -30,7 +31,13 @@ import javax.servlet.http.HttpServletResponse; import java.util.Arrays; import static javax.interceptor.Interceptor.Priority.PLATFORM_BEFORE; -import static org.apache.tomee.security.http.LoginToContinueMechanism.isOriginalRequestInSession; +import static javax.security.enterprise.AuthenticationStatus.SEND_FAILURE; +import static javax.security.enterprise.AuthenticationStatus.SUCCESS; +import static org.apache.tomee.security.http.LoginToContinueMechanism.getRequest; +import static org.apache.tomee.security.http.LoginToContinueMechanism.hasAuthentication; +import static org.apache.tomee.security.http.LoginToContinueMechanism.hasRequest; +import static org.apache.tomee.security.http.LoginToContinueMechanism.matchRequest; +import static org.apache.tomee.security.http.LoginToContinueMechanism.saveAuthentication; import static org.apache.tomee.security.http.LoginToContinueMechanism.saveRequest; @LoginToContinue @@ -90,7 +97,33 @@ public class LoginToContinueInterceptor { } if (isOnLoginPostback(httpMessageContext)) { - return null; + final AuthenticationStatus authenticationStatus = (AuthenticationStatus) invocationContext.proceed(); + + if (authenticationStatus.equals(SUCCESS)) { + if (httpMessageContext.getCallerPrincipal() == null) { + return SUCCESS; + } + + if (matchRequest(httpMessageContext.getRequest())) { + return SUCCESS; + } + + saveAuthentication(httpMessageContext.getRequest(), + httpMessageContext.getCallerPrincipal(), + httpMessageContext.getGroups()); + + final SavedRequest savedRequest = getRequest(httpMessageContext.getRequest()); + return httpMessageContext.redirect(savedRequest.getRequestURLWithQueryString()); + } + + if (authenticationStatus.equals(SEND_FAILURE)) { + final LoginToContinue loginToContinue = getLoginToContinue(invocationContext); + if (!loginToContinue.errorPage().isEmpty()) { + return httpMessageContext.forward(loginToContinue.errorPage()); + } + + return authenticationStatus; + } } if (isOnOriginalURLAfterAuthenticate(httpMessageContext)) { @@ -101,11 +134,11 @@ public class LoginToContinueInterceptor { } private boolean isOnInitialProtectedURL(final HttpMessageContext httpMessageContext) { - return httpMessageContext.isProtected() && !isOriginalRequestInSession(httpMessageContext.getRequest()); + return httpMessageContext.isProtected() && !hasRequest(httpMessageContext.getRequest()); } private boolean isOnLoginPostback(final HttpMessageContext httpMessageContext) { - return false; + return hasRequest(httpMessageContext.getRequest()) && !hasAuthentication(httpMessageContext.getRequest()); } private boolean isOnOriginalURLAfterAuthenticate(final HttpMessageContext httpMessageContext) { diff --git a/tomee/tomee-security/src/main/java/org/apache/tomee/security/http/LoginToContinueMechanism.java b/tomee/tomee-security/src/main/java/org/apache/tomee/security/http/LoginToContinueMechanism.java index 482bae6..e67b4b4 100644 --- a/tomee/tomee-security/src/main/java/org/apache/tomee/security/http/LoginToContinueMechanism.java +++ b/tomee/tomee-security/src/main/java/org/apache/tomee/security/http/LoginToContinueMechanism.java @@ -16,21 +16,24 @@ */ package org.apache.tomee.security.http; -import org.apache.catalina.authenticator.SavedRequest; import org.apache.tomcat.util.buf.ByteChunk; import javax.security.enterprise.authentication.mechanism.http.LoginToContinue; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; import java.io.IOException; import java.io.InputStream; +import java.security.Principal; import java.util.Enumeration; import java.util.Locale; +import java.util.Set; public interface LoginToContinueMechanism { int MAX_SAVE_POST_SIZE = 4 * 1024; String ORIGINAL_REQUEST = "org.apache.tomee.security.request.original"; + String AUTHENTICATION = "org.apache.tomee.security.request.authentication"; LoginToContinue getLoginToContinue(); @@ -80,12 +83,53 @@ public interface LoginToContinueMechanism { saved.setMethod(request.getMethod()); saved.setQueryString(request.getQueryString()); saved.setRequestURI(request.getRequestURI()); + saved.setRequestURL(request.getRequestURL().toString()); // Stash the SavedRequest in our session for later use request.getSession().setAttribute(ORIGINAL_REQUEST, saved); } - static boolean isOriginalRequestInSession(final HttpServletRequest request) { + static boolean matchRequest(final HttpServletRequest request) { + // Has a session been created? + final HttpSession session = request.getSession(false); + if (session == null) { + return false; + } + + // Is there a saved request? + final SavedRequest originalRequest = (SavedRequest) request.getSession().getAttribute(ORIGINAL_REQUEST); + if (originalRequest == null) { + return false; + } + + // Is there a saved principal? + /* + if (session.getNote(Constants.FORM_PRINCIPAL_NOTE) == null) { + return false; + } + */ + + // Does the request URI match? + final String requestURI = request.getRequestURI(); + return requestURI != null && requestURI.equals(originalRequest.getRequestURI()); + } + + static boolean hasRequest(final HttpServletRequest request) { return request.getSession().getAttribute(ORIGINAL_REQUEST) != null; } + + static SavedRequest getRequest(final HttpServletRequest request) { + return (SavedRequest) request.getSession().getAttribute(ORIGINAL_REQUEST); + } + + static void saveAuthentication(final HttpServletRequest request, + final Principal principal, + final Set<String> groups) { + final SavedAuthentication savedAuthentication = new SavedAuthentication(principal, groups); + request.getSession().setAttribute(AUTHENTICATION, savedAuthentication); + } + + static boolean hasAuthentication(final HttpServletRequest request) { + return request.getSession().getAttribute(AUTHENTICATION) != null; + } } diff --git a/tomee/tomee-security/src/main/java/org/apache/tomee/security/http/SavedAuthentication.java b/tomee/tomee-security/src/main/java/org/apache/tomee/security/http/SavedAuthentication.java new file mode 100644 index 0000000..5c30353 --- /dev/null +++ b/tomee/tomee-security/src/main/java/org/apache/tomee/security/http/SavedAuthentication.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.tomee.security.http; + + +import java.security.Principal; +import java.util.Set; + +import static java.util.Collections.unmodifiableSet; + +public final class SavedAuthentication { + private final Principal principal; + private final Set<String> groups; + + SavedAuthentication(final Principal principal, final Set<String> groups) { + this.principal = principal; + this.groups = unmodifiableSet(groups); + } + + public Principal getPrincipal() { + return principal; + } + + public Set<String> getGroups() { + return groups; + } +} diff --git a/tomee/tomee-security/src/main/java/org/apache/tomee/security/http/SavedRequest.java b/tomee/tomee-security/src/main/java/org/apache/tomee/security/http/SavedRequest.java new file mode 100644 index 0000000..ca49c53 --- /dev/null +++ b/tomee/tomee-security/src/main/java/org/apache/tomee/security/http/SavedRequest.java @@ -0,0 +1,178 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.tomee.security.http; + +import org.apache.tomcat.util.buf.ByteChunk; + +import javax.servlet.http.Cookie; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +/** + * Mostly copied from org.apache.catalina.authenticator.SavedRequest. + */ +public final class SavedRequest { + + SavedRequest() { + } + + /** + * The set of Cookies associated with this Request. + */ + private final List<Cookie> cookies = new ArrayList<>(); + + public void addCookie(Cookie cookie) { + cookies.add(cookie); + } + + public Iterator<Cookie> getCookies() { + return cookies.iterator(); + } + + + /** + * The set of Headers associated with this Request. Each key is a header + * name, while the value is a List containing one or more actual + * values for this header. The values are returned as an Iterator when + * you ask for them. + */ + private final Map<String, List<String>> headers = new HashMap<>(); + + public void addHeader(String name, String value) { + List<String> values = headers.get(name); + if (values == null) { + values = new ArrayList<>(); + headers.put(name, values); + } + values.add(value); + } + + public Iterator<String> getHeaderNames() { + return headers.keySet().iterator(); + } + + public Iterator<String> getHeaderValues(String name) { + List<String> values = headers.get(name); + if (values == null) { return Collections.emptyIterator(); } else { return values.iterator(); } + } + + + /** + * The set of Locales associated with this Request. + */ + private final List<Locale> locales = new ArrayList<>(); + + public void addLocale(Locale locale) { + locales.add(locale); + } + + public Iterator<Locale> getLocales() { + return locales.iterator(); + } + + + /** + * The request method used on this Request. + */ + private String method = null; + + public String getMethod() { + return this.method; + } + + public void setMethod(String method) { + this.method = method; + } + + + /** + * The query string associated with this Request. + */ + private String queryString = null; + + public String getQueryString() { + return this.queryString; + } + + public void setQueryString(String queryString) { + this.queryString = queryString; + } + + + /** + * The request URI associated with this Request. See javax.servlet.http.HttpServletRequest#getRequestURI(). + */ + private String requestURI = null; + + public String getRequestURI() { + return this.requestURI; + } + + public void setRequestURI(String requestURI) { + this.requestURI = requestURI; + } + + + /** + * The decode request URL associated with this Request. See javax.servlet.http.HttpServletRequest#getRequestURL(). + */ + private String requestURL = null; + + public String getRequestURL() { + return this.requestURL; + } + + public void setRequestURL(String requestURL) { + this.requestURL = requestURL; + } + + + /** + * The body of this request. + */ + private ByteChunk body = null; + + public ByteChunk getBody() { + return this.body; + } + + public void setBody(ByteChunk body) { + this.body = body; + } + + /** + * The content type of the request, used if this is a POST. + */ + private String contentType = null; + + public String getContentType() { + return this.contentType; + } + + public void setContentType(String contentType) { + this.contentType = contentType; + } + + public String getRequestURLWithQueryString() { + return queryString == null || queryString.isEmpty() ? requestURL : requestURL + "?" + queryString; + } +} diff --git a/tomee/tomee-security/src/main/java/org/apache/tomee/security/http/TomEEHttpMessageContext.java b/tomee/tomee-security/src/main/java/org/apache/tomee/security/http/TomEEHttpMessageContext.java index 4c087da..d67d74d 100644 --- a/tomee/tomee-security/src/main/java/org/apache/tomee/security/http/TomEEHttpMessageContext.java +++ b/tomee/tomee-security/src/main/java/org/apache/tomee/security/http/TomEEHttpMessageContext.java @@ -50,6 +50,9 @@ public class TomEEHttpMessageContext implements HttpMessageContext { private final Subject clientSubject; private final Subject serviceSubject; + private Principal principal; + private Set<String> groups; + private TomEEHttpMessageContext( final CallbackHandler handler, final MessageInfo messageInfo, @@ -190,10 +193,13 @@ public class TomEEHttpMessageContext implements HttpMessageContext { new CallerPrincipalCallback(clientSubject, principal), new GroupPrincipalCallback(clientSubject, groups.toArray(new String[groups.size()])) }); - } catch (IOException | UnsupportedCallbackException e) { + } catch (final IOException | UnsupportedCallbackException e) { e.printStackTrace(); } + this.principal = principal; + this.groups = groups; + return SUCCESS; } @@ -213,11 +219,11 @@ public class TomEEHttpMessageContext implements HttpMessageContext { @Override public Principal getCallerPrincipal() { - return null; + return principal; } @Override public Set<String> getGroups() { - return null; + return groups; } }
