You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by ff...@apache.org on 2013/07/29 11:31:49 UTC

svn commit: r1507984 - in /cxf/trunk/rt/transports/http/src/main: java/org/apache/cxf/transport/servlet/ java/org/apache/cxf/transport/servlet/servicelist/ resources/OSGI-INF/blueprint/

Author: ffang
Date: Mon Jul 29 09:31:48 2013
New Revision: 1507984

URL: http://svn.apache.org/r1507984
Log:
[CXF-5165]add a JAAS authenticator for ServiceListPage

Added:
    cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListJAASAuthenticator.java
Modified:
    cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/ServletController.java
    cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListGeneratorServlet.java
    cxf/trunk/rt/transports/http/src/main/resources/OSGI-INF/blueprint/osgiservlet.xml

Modified: cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/ServletController.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/ServletController.java?rev=1507984&r1=1507983&r2=1507984&view=diff
==============================================================================
--- cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/ServletController.java (original)
+++ cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/ServletController.java Mon Jul 29 09:31:48 2013
@@ -40,12 +40,17 @@ import org.apache.cxf.transport.http.Abs
 import org.apache.cxf.transport.http.DestinationRegistry;
 
 public class ServletController {
+    
+    public static final String AUTH_SERVICE_LIST = "auth.service.list";
+    public static final String AUTH_SERVICE_LIST_REALM = "auth.service.list.realm";
     protected static final String DEFAULT_LISTINGS_CLASSIFIER = "/services";
     private static final Logger LOG = LogUtils.getL7dLogger(ServletController.class);
     private static final String HTTP_PREFIX = "http";
-    
+        
     protected boolean isHideServiceList;
+    protected boolean isAuthServiceListPage;
     protected boolean disableAddressUpdates;
+    protected String authServiceListPageRealm;
     protected String forcedBaseAddress;
     protected String serviceListRelativePath = DEFAULT_LISTINGS_CLASSIFIER;
     protected ServletConfig servletConfig;
@@ -108,6 +113,17 @@ public class ServletController {
         if (!StringUtils.isEmpty(hideServiceList)) {
             this.isHideServiceList = Boolean.valueOf(hideServiceList);
         }
+        
+        String authServiceListPage = servletConfig.getInitParameter("service-list-page-authenticate");
+        if (!StringUtils.isEmpty(authServiceListPage)) {
+            this.isAuthServiceListPage = Boolean.valueOf(authServiceListPage);
+        }
+        
+        String authServiceListRealm = servletConfig.getInitParameter("service-list-page-authenticate-realm");
+        if (!StringUtils.isEmpty(authServiceListRealm)) {
+            this.authServiceListPageRealm = authServiceListRealm;
+        }
+        
         String isDisableAddressUpdates = servletConfig.getInitParameter("disable-address-updates");
         if (!StringUtils.isEmpty(isDisableAddressUpdates)) {
             this.disableAddressUpdates = Boolean.valueOf(isDisableAddressUpdates);
@@ -143,6 +159,9 @@ public class ServletController {
                     || request.getRequestURI().endsWith(serviceListRelativePath + "/")
                     || StringUtils.isEmpty(pathInfo)
                     || "/".equals(pathInfo))) {
+                    if (isAuthServiceListPage) {
+                        setAuthServiceListPageAttribute(request);
+                    }
                     setBaseURLAttribute(request);
                     serviceListGenerator.service(request, res);
                 } else {
@@ -188,6 +207,12 @@ public class ServletController {
         return true;
     }
 
+    private void setAuthServiceListPageAttribute(HttpServletRequest request) {
+        request.setAttribute(ServletController.AUTH_SERVICE_LIST, this.isAuthServiceListPage);
+        request.setAttribute(ServletController.AUTH_SERVICE_LIST_REALM, this.authServiceListPageRealm);
+        
+    }
+
     public void invokeDestination(final HttpServletRequest request, HttpServletResponse response,
                                   AbstractHTTPDestination d) throws ServletException {
         if (LOG.isLoggable(Level.FINE)) {

Modified: cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListGeneratorServlet.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListGeneratorServlet.java?rev=1507984&r1=1507983&r2=1507984&view=diff
==============================================================================
--- cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListGeneratorServlet.java (original)
+++ cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListGeneratorServlet.java Mon Jul 29 09:31:48 2013
@@ -39,6 +39,7 @@ import org.apache.cxf.message.Message;
 import org.apache.cxf.service.model.EndpointInfo;
 import org.apache.cxf.transport.AbstractDestination;
 import org.apache.cxf.transport.http.DestinationRegistry;
+import org.apache.cxf.transport.servlet.ServletController;
 
 public class ServiceListGeneratorServlet extends HttpServlet {
     private static final long serialVersionUID = -113918058557537996L;
@@ -67,6 +68,19 @@ public class ServiceListGeneratorServlet
     @Override
     public void service(HttpServletRequest request, 
                         HttpServletResponse response) throws ServletException, IOException {
+        Object obj = request.getAttribute(ServletController.AUTH_SERVICE_LIST);
+        boolean isAuthServiceList = false;
+        if (obj != null) {
+            isAuthServiceList = Boolean.valueOf(obj.toString());
+        }
+        if (isAuthServiceList) {
+            String authServiceListRealm = (String)request.getAttribute(ServletController.AUTH_SERVICE_LIST_REALM);
+            ServiceListJAASAuthenticator authenticator = new ServiceListJAASAuthenticator();
+            authenticator.setRealm(authServiceListRealm);
+            if (!authenticator.authenticate(request, response)) {
+                return;
+            }
+        }
         PrintWriter writer = response.getWriter();
         AbstractDestination[] destinations = destinationRegistry.getSortedDestinations();
         if (request.getParameter("stylesheet") != null) {

Added: cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListJAASAuthenticator.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListJAASAuthenticator.java?rev=1507984&view=auto
==============================================================================
--- cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListJAASAuthenticator.java (added)
+++ cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListJAASAuthenticator.java Mon Jul 29 09:31:48 2013
@@ -0,0 +1,163 @@
+/**
+ * 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.cxf.transport.servlet.servicelist;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.GeneralSecurityException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.login.AccountException;
+import javax.security.auth.login.FailedLoginException;
+import javax.security.auth.login.LoginContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.common.util.Base64Exception;
+import org.apache.cxf.common.util.Base64Utility;
+import org.apache.cxf.transport.http.blueprint.HttpDestinationBPBeanDefinitionParser;
+
+
+
+public class ServiceListJAASAuthenticator {
+
+    private static final Logger LOG = LogUtils.getL7dLogger(HttpDestinationBPBeanDefinitionParser.class);
+
+    private static final String HEADER_WWW_AUTHENTICATE = "WWW-Authenticate";
+
+    private static final String HEADER_AUTHORIZATION = "Authorization";
+
+    private static final String AUTHENTICATION_SCHEME_BASIC = "Basic";
+
+    private String realm;
+        
+    public String getRealm() {
+        return realm;
+    }
+
+    public void setRealm(String realm) {
+        this.realm = realm;
+    }
+
+    
+    public Object authenticate(final String username, final String password) {
+        return doAuthenticate(username, password);
+    }
+
+    public Subject doAuthenticate(final String username, final String password) {
+        try {
+            Subject subject = new Subject();
+            LoginContext loginContext = new LoginContext(realm, subject, new CallbackHandler() {
+                public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+                    for (int i = 0; i < callbacks.length; i++) {
+                        if (callbacks[i] instanceof NameCallback) {
+                            ((NameCallback)callbacks[i]).setName(username);
+                        } else if (callbacks[i] instanceof PasswordCallback) {
+                            ((PasswordCallback)callbacks[i]).setPassword(password.toCharArray());
+                        } else {
+                            throw new UnsupportedCallbackException(callbacks[i]);
+                        }
+                    }
+                }
+            });
+            loginContext.login();
+            return subject;
+        } catch (FailedLoginException e) {
+            LOG.log(Level.FINE, "Login failed ", e);
+            return null;
+        } catch (AccountException e) {
+            LOG.log(Level.WARNING, "Account failure ",  e);
+            return null;
+        } catch (GeneralSecurityException e) {
+            LOG.log(Level.SEVERE, "General Security Exception ", e);
+            return null;
+        }
+    }
+
+    public boolean authenticate(HttpServletRequest request, HttpServletResponse response) {
+        // Return immediately if the header is missing
+        String authHeader = request.getHeader(HEADER_AUTHORIZATION);
+        if (authHeader != null && authHeader.length() > 0) {
+
+            // Get the authType (Basic, Digest) and authInfo (user/password)
+            // from the header
+            authHeader = authHeader.trim();
+            int blank = authHeader.indexOf(' ');
+            if (blank > 0) {
+                String authType = authHeader.substring(0, blank);
+                String authInfo = authHeader.substring(blank).trim();
+
+                
+                if (authType.equalsIgnoreCase(AUTHENTICATION_SCHEME_BASIC)) {
+                    try {
+                        String srcString = base64Decode(authInfo);
+
+                        int i = srcString.indexOf(':');
+                        String username = srcString.substring(0, i);
+                        String password = srcString.substring(i + 1);
+
+                        // authenticate
+                        Subject subject = doAuthenticate(username, password);
+                        if (subject != null) {
+                            return true;
+                        }
+                       
+                    } catch (Exception e) {
+                        // Ignore
+                    }
+                }
+            }
+        }
+
+        // request authentication
+        try {
+            response.setHeader(HEADER_WWW_AUTHENTICATE, AUTHENTICATION_SCHEME_BASIC + " realm=\""
+                                                        + this.realm + "\"");
+            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+            response.setContentLength(0);
+            response.flushBuffer();
+        } catch (IOException ioe) {
+            // failed sending the response ... cannot do anything about it
+        }
+
+        // inform HttpService that authentication failed
+        return false;
+    }
+    
+    private static String base64Decode(String srcString) {
+        byte[] transformed = null;
+        try {
+            transformed = Base64Utility.decode(srcString);
+            return new String(transformed, "ISO-8859-1");
+        } catch (UnsupportedEncodingException uee) {
+            return srcString;
+        } catch (Base64Exception e) {
+            return srcString;
+        }
+    }
+
+}

Modified: cxf/trunk/rt/transports/http/src/main/resources/OSGI-INF/blueprint/osgiservlet.xml
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/transports/http/src/main/resources/OSGI-INF/blueprint/osgiservlet.xml?rev=1507984&r1=1507983&r2=1507984&view=diff
==============================================================================
--- cxf/trunk/rt/transports/http/src/main/resources/OSGI-INF/blueprint/osgiservlet.xml (original)
+++ cxf/trunk/rt/transports/http/src/main/resources/OSGI-INF/blueprint/osgiservlet.xml Mon Jul 29 09:31:48 2013
@@ -39,7 +39,8 @@ under the License.
       <cm:property name="org.apache.cxf.servlet.redirect-servlet-name" value=""/>
       <cm:property name="org.apache.cxf.servlet.redirect-servlet-path" value=""/>
       <cm:property name="org.apache.cxf.servlet.service-list-all-contexts" value=""/>
-
+      <cm:property name="org.apache.cxf.servlet.service-list-page-authenticate" value="false"/>
+      <cm:property name="org.apache.cxf.servlet.service-list-page-authenticate-realm" value="karaf"/>
     </cm:default-properties>
 
   </cm:property-placeholder>
@@ -64,6 +65,8 @@ under the License.
       <entry key="redirect-servlet-name" value="${org.apache.cxf.servlet.redirect-servlet-name}"/>
       <entry key="redirect-servlet-path" value="${org.apache.cxf.servlet.redirect-servlet-path}"/>
       <entry key="service-list-all-contexts" value="${org.apache.cxf.servlet.service-list-all-contexts}"/>
+      <entry key="service-list-page-authenticate" value="${org.apache.cxf.servlet.service-list-page-authenticate}"/>
+      <entry key="service-list-page-authenticate-realm" value="${org.apache.cxf.servlet.service-list-page-authenticate-realm}"/>
     </service-properties>
   </service>
 



Re: svn commit: r1507984 - in /cxf/trunk/rt/transports/http/src/main: java/org/apache/cxf/transport/servlet/ java/org/apache/cxf/transport/servlet/servicelist/ resources/OSGI-INF/blueprint/

Posted by Sergey Beryozkin <sb...@gmail.com>.
Actually, does not make sense, obviously the request does not continue 
after that, got confused

Sergey

On 29/07/13 10:41, Sergey Beryozkin wrote:
> Hi Freeman
>
> Can you please update ServiceListGeneratorServlet to actually remove the
> temp HTTPServletRequest attributes - because they are not needed any
> more after that ?
>
> The reason is that these attributes will leak into JAX-RS
> ContainerRequestFilter.getProperties() - unfortunately this method has
> been tied to HTTPServletRequest attributes,
>
> Thanks, Sergey
>
> Thanks, Sergey
> On 29/07/13 10:31, ffang@apache.org wrote:
>> Author: ffang
>> Date: Mon Jul 29 09:31:48 2013
>> New Revision: 1507984
>>
>> URL: http://svn.apache.org/r1507984
>> Log:
>> [CXF-5165]add a JAAS authenticator for ServiceListPage
>>
>> Added:
>>
>> cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListJAASAuthenticator.java
>>
>> Modified:
>>
>> cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/ServletController.java
>>
>>
>> cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListGeneratorServlet.java
>>
>>
>> cxf/trunk/rt/transports/http/src/main/resources/OSGI-INF/blueprint/osgiservlet.xml
>>
>>
>> Modified:
>> cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/ServletController.java
>>
>> URL:
>> http://svn.apache.org/viewvc/cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/ServletController.java?rev=1507984&r1=1507983&r2=1507984&view=diff
>>
>> ==============================================================================
>>
>> ---
>> cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/ServletController.java
>> (original)
>> +++
>> cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/ServletController.java
>> Mon Jul 29 09:31:48 2013
>> @@ -40,12 +40,17 @@ import org.apache.cxf.transport.http.Abs
>>   import org.apache.cxf.transport.http.DestinationRegistry;
>>
>>   public class ServletController {
>> +
>> +    public static final String AUTH_SERVICE_LIST = "auth.service.list";
>> +    public static final String AUTH_SERVICE_LIST_REALM =
>> "auth.service.list.realm";
>>       protected static final String DEFAULT_LISTINGS_CLASSIFIER =
>> "/services";
>>       private static final Logger LOG =
>> LogUtils.getL7dLogger(ServletController.class);
>>       private static final String HTTP_PREFIX = "http";
>> -
>> +
>>       protected boolean isHideServiceList;
>> +    protected boolean isAuthServiceListPage;
>>       protected boolean disableAddressUpdates;
>> +    protected String authServiceListPageRealm;
>>       protected String forcedBaseAddress;
>>       protected String serviceListRelativePath =
>> DEFAULT_LISTINGS_CLASSIFIER;
>>       protected ServletConfig servletConfig;
>> @@ -108,6 +113,17 @@ public class ServletController {
>>           if (!StringUtils.isEmpty(hideServiceList)) {
>>               this.isHideServiceList = Boolean.valueOf(hideServiceList);
>>           }
>> +
>> +        String authServiceListPage =
>> servletConfig.getInitParameter("service-list-page-authenticate");
>> +        if (!StringUtils.isEmpty(authServiceListPage)) {
>> +            this.isAuthServiceListPage =
>> Boolean.valueOf(authServiceListPage);
>> +        }
>> +
>> +        String authServiceListRealm =
>> servletConfig.getInitParameter("service-list-page-authenticate-realm");
>> +        if (!StringUtils.isEmpty(authServiceListRealm)) {
>> +            this.authServiceListPageRealm = authServiceListRealm;
>> +        }
>> +
>>           String isDisableAddressUpdates =
>> servletConfig.getInitParameter("disable-address-updates");
>>           if (!StringUtils.isEmpty(isDisableAddressUpdates)) {
>>               this.disableAddressUpdates =
>> Boolean.valueOf(isDisableAddressUpdates);
>> @@ -143,6 +159,9 @@ public class ServletController {
>>                       ||
>> request.getRequestURI().endsWith(serviceListRelativePath + "/")
>>                       || StringUtils.isEmpty(pathInfo)
>>                       || "/".equals(pathInfo))) {
>> +                    if (isAuthServiceListPage) {
>> +                        setAuthServiceListPageAttribute(request);
>> +                    }
>>                       setBaseURLAttribute(request);
>>                       serviceListGenerator.service(request, res);
>>                   } else {
>> @@ -188,6 +207,12 @@ public class ServletController {
>>           return true;
>>       }
>>
>> +    private void setAuthServiceListPageAttribute(HttpServletRequest
>> request) {
>> +        request.setAttribute(ServletController.AUTH_SERVICE_LIST,
>> this.isAuthServiceListPage);
>> +
>> request.setAttribute(ServletController.AUTH_SERVICE_LIST_REALM,
>> this.authServiceListPageRealm);
>> +
>> +    }
>> +
>>       public void invokeDestination(final HttpServletRequest request,
>> HttpServletResponse response,
>>                                     AbstractHTTPDestination d) throws
>> ServletException {
>>           if (LOG.isLoggable(Level.FINE)) {
>>
>> Modified:
>> cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListGeneratorServlet.java
>>
>> URL:
>> http://svn.apache.org/viewvc/cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListGeneratorServlet.java?rev=1507984&r1=1507983&r2=1507984&view=diff
>>
>> ==============================================================================
>>
>> ---
>> cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListGeneratorServlet.java
>> (original)
>> +++
>> cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListGeneratorServlet.java
>> Mon Jul 29 09:31:48 2013
>> @@ -39,6 +39,7 @@ import org.apache.cxf.message.Message;
>>   import org.apache.cxf.service.model.EndpointInfo;
>>   import org.apache.cxf.transport.AbstractDestination;
>>   import org.apache.cxf.transport.http.DestinationRegistry;
>> +import org.apache.cxf.transport.servlet.ServletController;
>>
>>   public class ServiceListGeneratorServlet extends HttpServlet {
>>       private static final long serialVersionUID = -113918058557537996L;
>> @@ -67,6 +68,19 @@ public class ServiceListGeneratorServlet
>>       @Override
>>       public void service(HttpServletRequest request,
>>                           HttpServletResponse response) throws
>> ServletException, IOException {
>> +        Object obj =
>> request.getAttribute(ServletController.AUTH_SERVICE_LIST);
>> +        boolean isAuthServiceList = false;
>> +        if (obj != null) {
>> +            isAuthServiceList = Boolean.valueOf(obj.toString());
>> +        }
>> +        if (isAuthServiceList) {
>> +            String authServiceListRealm =
>> (String)request.getAttribute(ServletController.AUTH_SERVICE_LIST_REALM);
>> +            ServiceListJAASAuthenticator authenticator = new
>> ServiceListJAASAuthenticator();
>> +            authenticator.setRealm(authServiceListRealm);
>> +            if (!authenticator.authenticate(request, response)) {
>> +                return;
>> +            }
>> +        }
>>           PrintWriter writer = response.getWriter();
>>           AbstractDestination[] destinations =
>> destinationRegistry.getSortedDestinations();
>>           if (request.getParameter("stylesheet") != null) {
>>
>> Added:
>> cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListJAASAuthenticator.java
>>
>> URL:
>> http://svn.apache.org/viewvc/cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListJAASAuthenticator.java?rev=1507984&view=auto
>>
>> ==============================================================================
>>
>> ---
>> cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListJAASAuthenticator.java
>> (added)
>> +++
>> cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListJAASAuthenticator.java
>> Mon Jul 29 09:31:48 2013
>> @@ -0,0 +1,163 @@
>> +/**
>> + * 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.cxf.transport.servlet.servicelist;
>> +
>> +import java.io.IOException;
>> +import java.io.UnsupportedEncodingException;
>> +import java.security.GeneralSecurityException;
>> +import java.util.logging.Level;
>> +import java.util.logging.Logger;
>> +
>> +import javax.security.auth.Subject;
>> +import javax.security.auth.callback.Callback;
>> +import javax.security.auth.callback.CallbackHandler;
>> +import javax.security.auth.callback.NameCallback;
>> +import javax.security.auth.callback.PasswordCallback;
>> +import javax.security.auth.callback.UnsupportedCallbackException;
>> +import javax.security.auth.login.AccountException;
>> +import javax.security.auth.login.FailedLoginException;
>> +import javax.security.auth.login.LoginContext;
>> +import javax.servlet.http.HttpServletRequest;
>> +import javax.servlet.http.HttpServletResponse;
>> +
>> +import org.apache.cxf.common.logging.LogUtils;
>> +import org.apache.cxf.common.util.Base64Exception;
>> +import org.apache.cxf.common.util.Base64Utility;
>> +import
>> org.apache.cxf.transport.http.blueprint.HttpDestinationBPBeanDefinitionParser;
>>
>> +
>> +
>> +
>> +public class ServiceListJAASAuthenticator {
>> +
>> +    private static final Logger LOG =
>> LogUtils.getL7dLogger(HttpDestinationBPBeanDefinitionParser.class);
>> +
>> +    private static final String HEADER_WWW_AUTHENTICATE =
>> "WWW-Authenticate";
>> +
>> +    private static final String HEADER_AUTHORIZATION = "Authorization";
>> +
>> +    private static final String AUTHENTICATION_SCHEME_BASIC = "Basic";
>> +
>> +    private String realm;
>> +
>> +    public String getRealm() {
>> +        return realm;
>> +    }
>> +
>> +    public void setRealm(String realm) {
>> +        this.realm = realm;
>> +    }
>> +
>> +
>> +    public Object authenticate(final String username, final String
>> password) {
>> +        return doAuthenticate(username, password);
>> +    }
>> +
>> +    public Subject doAuthenticate(final String username, final String
>> password) {
>> +        try {
>> +            Subject subject = new Subject();
>> +            LoginContext loginContext = new LoginContext(realm,
>> subject, new CallbackHandler() {
>> +                public void handle(Callback[] callbacks) throws
>> IOException, UnsupportedCallbackException {
>> +                    for (int i = 0; i < callbacks.length; i++) {
>> +                        if (callbacks[i] instanceof NameCallback) {
>> +
>> ((NameCallback)callbacks[i]).setName(username);
>> +                        } else if (callbacks[i] instanceof
>> PasswordCallback) {
>> +
>> ((PasswordCallback)callbacks[i]).setPassword(password.toCharArray());
>> +                        } else {
>> +                            throw new
>> UnsupportedCallbackException(callbacks[i]);
>> +                        }
>> +                    }
>> +                }
>> +            });
>> +            loginContext.login();
>> +            return subject;
>> +        } catch (FailedLoginException e) {
>> +            LOG.log(Level.FINE, "Login failed ", e);
>> +            return null;
>> +        } catch (AccountException e) {
>> +            LOG.log(Level.WARNING, "Account failure ",  e);
>> +            return null;
>> +        } catch (GeneralSecurityException e) {
>> +            LOG.log(Level.SEVERE, "General Security Exception ", e);
>> +            return null;
>> +        }
>> +    }
>> +
>> +    public boolean authenticate(HttpServletRequest request,
>> HttpServletResponse response) {
>> +        // Return immediately if the header is missing
>> +        String authHeader = request.getHeader(HEADER_AUTHORIZATION);
>> +        if (authHeader != null && authHeader.length() > 0) {
>> +
>> +            // Get the authType (Basic, Digest) and authInfo
>> (user/password)
>> +            // from the header
>> +            authHeader = authHeader.trim();
>> +            int blank = authHeader.indexOf(' ');
>> +            if (blank > 0) {
>> +                String authType = authHeader.substring(0, blank);
>> +                String authInfo = authHeader.substring(blank).trim();
>> +
>> +
>> +                if
>> (authType.equalsIgnoreCase(AUTHENTICATION_SCHEME_BASIC)) {
>> +                    try {
>> +                        String srcString = base64Decode(authInfo);
>> +
>> +                        int i = srcString.indexOf(':');
>> +                        String username = srcString.substring(0, i);
>> +                        String password = srcString.substring(i + 1);
>> +
>> +                        // authenticate
>> +                        Subject subject = doAuthenticate(username,
>> password);
>> +                        if (subject != null) {
>> +                            return true;
>> +                        }
>> +
>> +                    } catch (Exception e) {
>> +                        // Ignore
>> +                    }
>> +                }
>> +            }
>> +        }
>> +
>> +        // request authentication
>> +        try {
>> +            response.setHeader(HEADER_WWW_AUTHENTICATE,
>> AUTHENTICATION_SCHEME_BASIC + " realm=\""
>> +                                                        + this.realm
>> + "\"");
>> +            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
>> +            response.setContentLength(0);
>> +            response.flushBuffer();
>> +        } catch (IOException ioe) {
>> +            // failed sending the response ... cannot do anything
>> about it
>> +        }
>> +
>> +        // inform HttpService that authentication failed
>> +        return false;
>> +    }
>> +
>> +    private static String base64Decode(String srcString) {
>> +        byte[] transformed = null;
>> +        try {
>> +            transformed = Base64Utility.decode(srcString);
>> +            return new String(transformed, "ISO-8859-1");
>> +        } catch (UnsupportedEncodingException uee) {
>> +            return srcString;
>> +        } catch (Base64Exception e) {
>> +            return srcString;
>> +        }
>> +    }
>> +
>> +}
>>
>> Modified:
>> cxf/trunk/rt/transports/http/src/main/resources/OSGI-INF/blueprint/osgiservlet.xml
>>
>> URL:
>> http://svn.apache.org/viewvc/cxf/trunk/rt/transports/http/src/main/resources/OSGI-INF/blueprint/osgiservlet.xml?rev=1507984&r1=1507983&r2=1507984&view=diff
>>
>> ==============================================================================
>>
>> ---
>> cxf/trunk/rt/transports/http/src/main/resources/OSGI-INF/blueprint/osgiservlet.xml
>> (original)
>> +++
>> cxf/trunk/rt/transports/http/src/main/resources/OSGI-INF/blueprint/osgiservlet.xml
>> Mon Jul 29 09:31:48 2013
>> @@ -39,7 +39,8 @@ under the License.
>>         <cm:property
>> name="org.apache.cxf.servlet.redirect-servlet-name" value=""/>
>>         <cm:property
>> name="org.apache.cxf.servlet.redirect-servlet-path" value=""/>
>>         <cm:property
>> name="org.apache.cxf.servlet.service-list-all-contexts" value=""/>
>> -
>> +      <cm:property
>> name="org.apache.cxf.servlet.service-list-page-authenticate"
>> value="false"/>
>> +      <cm:property
>> name="org.apache.cxf.servlet.service-list-page-authenticate-realm"
>> value="karaf"/>
>>       </cm:default-properties>
>>
>>     </cm:property-placeholder>
>> @@ -64,6 +65,8 @@ under the License.
>>         <entry key="redirect-servlet-name"
>> value="${org.apache.cxf.servlet.redirect-servlet-name}"/>
>>         <entry key="redirect-servlet-path"
>> value="${org.apache.cxf.servlet.redirect-servlet-path}"/>
>>         <entry key="service-list-all-contexts"
>> value="${org.apache.cxf.servlet.service-list-all-contexts}"/>
>> +      <entry key="service-list-page-authenticate"
>> value="${org.apache.cxf.servlet.service-list-page-authenticate}"/>
>> +      <entry key="service-list-page-authenticate-realm"
>> value="${org.apache.cxf.servlet.service-list-page-authenticate-realm}"/>
>>       </service-properties>
>>     </service>
>>
>>
>>
>
>


Re: svn commit: r1507984 - in /cxf/trunk/rt/transports/http/src/main: java/org/apache/cxf/transport/servlet/ java/org/apache/cxf/transport/servlet/servicelist/ resources/OSGI-INF/blueprint/

Posted by Freeman Fang <fr...@gmail.com>.
Hi Sergey,

Done, removed unnecessary attributes from HttpServletRequest if pass authentication.

Cheers
-------------
Freeman(Yue) Fang

Red Hat, Inc. 
FuseSource is now part of Red Hat
Web: http://fusesource.com | http://www.redhat.com/
Twitter: freemanfang
Blog: http://freemanfang.blogspot.com
http://blog.sina.com.cn/u/1473905042
weibo: @Freeman小屋



On 2013-7-29, at 下午5:41, Sergey Beryozkin wrote:

> Hi Freeman
> 
> Can you please update ServiceListGeneratorServlet to actually remove the temp HTTPServletRequest attributes - because they are not needed any more after that ?
> 
> The reason is that these attributes will leak into JAX-RS ContainerRequestFilter.getProperties() - unfortunately this method has been tied to HTTPServletRequest attributes,
> 
> Thanks, Sergey
> 
> Thanks, Sergey
> On 29/07/13 10:31, ffang@apache.org wrote:
>> Author: ffang
>> Date: Mon Jul 29 09:31:48 2013
>> New Revision: 1507984
>> 
>> URL: http://svn.apache.org/r1507984
>> Log:
>> [CXF-5165]add a JAAS authenticator for ServiceListPage
>> 
>> Added:
>>     cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListJAASAuthenticator.java
>> Modified:
>>     cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/ServletController.java
>>     cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListGeneratorServlet.java
>>     cxf/trunk/rt/transports/http/src/main/resources/OSGI-INF/blueprint/osgiservlet.xml
>> 
>> Modified: cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/ServletController.java
>> URL: http://svn.apache.org/viewvc/cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/ServletController.java?rev=1507984&r1=1507983&r2=1507984&view=diff
>> ==============================================================================
>> --- cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/ServletController.java (original)
>> +++ cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/ServletController.java Mon Jul 29 09:31:48 2013
>> @@ -40,12 +40,17 @@ import org.apache.cxf.transport.http.Abs
>>  import org.apache.cxf.transport.http.DestinationRegistry;
>> 
>>  public class ServletController {
>> +
>> +    public static final String AUTH_SERVICE_LIST = "auth.service.list";
>> +    public static final String AUTH_SERVICE_LIST_REALM = "auth.service.list.realm";
>>      protected static final String DEFAULT_LISTINGS_CLASSIFIER = "/services";
>>      private static final Logger LOG = LogUtils.getL7dLogger(ServletController.class);
>>      private static final String HTTP_PREFIX = "http";
>> -
>> +
>>      protected boolean isHideServiceList;
>> +    protected boolean isAuthServiceListPage;
>>      protected boolean disableAddressUpdates;
>> +    protected String authServiceListPageRealm;
>>      protected String forcedBaseAddress;
>>      protected String serviceListRelativePath = DEFAULT_LISTINGS_CLASSIFIER;
>>      protected ServletConfig servletConfig;
>> @@ -108,6 +113,17 @@ public class ServletController {
>>          if (!StringUtils.isEmpty(hideServiceList)) {
>>              this.isHideServiceList = Boolean.valueOf(hideServiceList);
>>          }
>> +
>> +        String authServiceListPage = servletConfig.getInitParameter("service-list-page-authenticate");
>> +        if (!StringUtils.isEmpty(authServiceListPage)) {
>> +            this.isAuthServiceListPage = Boolean.valueOf(authServiceListPage);
>> +        }
>> +
>> +        String authServiceListRealm = servletConfig.getInitParameter("service-list-page-authenticate-realm");
>> +        if (!StringUtils.isEmpty(authServiceListRealm)) {
>> +            this.authServiceListPageRealm = authServiceListRealm;
>> +        }
>> +
>>          String isDisableAddressUpdates = servletConfig.getInitParameter("disable-address-updates");
>>          if (!StringUtils.isEmpty(isDisableAddressUpdates)) {
>>              this.disableAddressUpdates = Boolean.valueOf(isDisableAddressUpdates);
>> @@ -143,6 +159,9 @@ public class ServletController {
>>                      || request.getRequestURI().endsWith(serviceListRelativePath + "/")
>>                      || StringUtils.isEmpty(pathInfo)
>>                      || "/".equals(pathInfo))) {
>> +                    if (isAuthServiceListPage) {
>> +                        setAuthServiceListPageAttribute(request);
>> +                    }
>>                      setBaseURLAttribute(request);
>>                      serviceListGenerator.service(request, res);
>>                  } else {
>> @@ -188,6 +207,12 @@ public class ServletController {
>>          return true;
>>      }
>> 
>> +    private void setAuthServiceListPageAttribute(HttpServletRequest request) {
>> +        request.setAttribute(ServletController.AUTH_SERVICE_LIST, this.isAuthServiceListPage);
>> +        request.setAttribute(ServletController.AUTH_SERVICE_LIST_REALM, this.authServiceListPageRealm);
>> +
>> +    }
>> +
>>      public void invokeDestination(final HttpServletRequest request, HttpServletResponse response,
>>                                    AbstractHTTPDestination d) throws ServletException {
>>          if (LOG.isLoggable(Level.FINE)) {
>> 
>> Modified: cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListGeneratorServlet.java
>> URL: http://svn.apache.org/viewvc/cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListGeneratorServlet.java?rev=1507984&r1=1507983&r2=1507984&view=diff
>> ==============================================================================
>> --- cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListGeneratorServlet.java (original)
>> +++ cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListGeneratorServlet.java Mon Jul 29 09:31:48 2013
>> @@ -39,6 +39,7 @@ import org.apache.cxf.message.Message;
>>  import org.apache.cxf.service.model.EndpointInfo;
>>  import org.apache.cxf.transport.AbstractDestination;
>>  import org.apache.cxf.transport.http.DestinationRegistry;
>> +import org.apache.cxf.transport.servlet.ServletController;
>> 
>>  public class ServiceListGeneratorServlet extends HttpServlet {
>>      private static final long serialVersionUID = -113918058557537996L;
>> @@ -67,6 +68,19 @@ public class ServiceListGeneratorServlet
>>      @Override
>>      public void service(HttpServletRequest request,
>>                          HttpServletResponse response) throws ServletException, IOException {
>> +        Object obj = request.getAttribute(ServletController.AUTH_SERVICE_LIST);
>> +        boolean isAuthServiceList = false;
>> +        if (obj != null) {
>> +            isAuthServiceList = Boolean.valueOf(obj.toString());
>> +        }
>> +        if (isAuthServiceList) {
>> +            String authServiceListRealm = (String)request.getAttribute(ServletController.AUTH_SERVICE_LIST_REALM);
>> +            ServiceListJAASAuthenticator authenticator = new ServiceListJAASAuthenticator();
>> +            authenticator.setRealm(authServiceListRealm);
>> +            if (!authenticator.authenticate(request, response)) {
>> +                return;
>> +            }
>> +        }
>>          PrintWriter writer = response.getWriter();
>>          AbstractDestination[] destinations = destinationRegistry.getSortedDestinations();
>>          if (request.getParameter("stylesheet") != null) {
>> 
>> Added: cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListJAASAuthenticator.java
>> URL: http://svn.apache.org/viewvc/cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListJAASAuthenticator.java?rev=1507984&view=auto
>> ==============================================================================
>> --- cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListJAASAuthenticator.java (added)
>> +++ cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListJAASAuthenticator.java Mon Jul 29 09:31:48 2013
>> @@ -0,0 +1,163 @@
>> +/**
>> + * 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.cxf.transport.servlet.servicelist;
>> +
>> +import java.io.IOException;
>> +import java.io.UnsupportedEncodingException;
>> +import java.security.GeneralSecurityException;
>> +import java.util.logging.Level;
>> +import java.util.logging.Logger;
>> +
>> +import javax.security.auth.Subject;
>> +import javax.security.auth.callback.Callback;
>> +import javax.security.auth.callback.CallbackHandler;
>> +import javax.security.auth.callback.NameCallback;
>> +import javax.security.auth.callback.PasswordCallback;
>> +import javax.security.auth.callback.UnsupportedCallbackException;
>> +import javax.security.auth.login.AccountException;
>> +import javax.security.auth.login.FailedLoginException;
>> +import javax.security.auth.login.LoginContext;
>> +import javax.servlet.http.HttpServletRequest;
>> +import javax.servlet.http.HttpServletResponse;
>> +
>> +import org.apache.cxf.common.logging.LogUtils;
>> +import org.apache.cxf.common.util.Base64Exception;
>> +import org.apache.cxf.common.util.Base64Utility;
>> +import org.apache.cxf.transport.http.blueprint.HttpDestinationBPBeanDefinitionParser;
>> +
>> +
>> +
>> +public class ServiceListJAASAuthenticator {
>> +
>> +    private static final Logger LOG = LogUtils.getL7dLogger(HttpDestinationBPBeanDefinitionParser.class);
>> +
>> +    private static final String HEADER_WWW_AUTHENTICATE = "WWW-Authenticate";
>> +
>> +    private static final String HEADER_AUTHORIZATION = "Authorization";
>> +
>> +    private static final String AUTHENTICATION_SCHEME_BASIC = "Basic";
>> +
>> +    private String realm;
>> +
>> +    public String getRealm() {
>> +        return realm;
>> +    }
>> +
>> +    public void setRealm(String realm) {
>> +        this.realm = realm;
>> +    }
>> +
>> +
>> +    public Object authenticate(final String username, final String password) {
>> +        return doAuthenticate(username, password);
>> +    }
>> +
>> +    public Subject doAuthenticate(final String username, final String password) {
>> +        try {
>> +            Subject subject = new Subject();
>> +            LoginContext loginContext = new LoginContext(realm, subject, new CallbackHandler() {
>> +                public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
>> +                    for (int i = 0; i < callbacks.length; i++) {
>> +                        if (callbacks[i] instanceof NameCallback) {
>> +                            ((NameCallback)callbacks[i]).setName(username);
>> +                        } else if (callbacks[i] instanceof PasswordCallback) {
>> +                            ((PasswordCallback)callbacks[i]).setPassword(password.toCharArray());
>> +                        } else {
>> +                            throw new UnsupportedCallbackException(callbacks[i]);
>> +                        }
>> +                    }
>> +                }
>> +            });
>> +            loginContext.login();
>> +            return subject;
>> +        } catch (FailedLoginException e) {
>> +            LOG.log(Level.FINE, "Login failed ", e);
>> +            return null;
>> +        } catch (AccountException e) {
>> +            LOG.log(Level.WARNING, "Account failure ",  e);
>> +            return null;
>> +        } catch (GeneralSecurityException e) {
>> +            LOG.log(Level.SEVERE, "General Security Exception ", e);
>> +            return null;
>> +        }
>> +    }
>> +
>> +    public boolean authenticate(HttpServletRequest request, HttpServletResponse response) {
>> +        // Return immediately if the header is missing
>> +        String authHeader = request.getHeader(HEADER_AUTHORIZATION);
>> +        if (authHeader != null && authHeader.length() > 0) {
>> +
>> +            // Get the authType (Basic, Digest) and authInfo (user/password)
>> +            // from the header
>> +            authHeader = authHeader.trim();
>> +            int blank = authHeader.indexOf(' ');
>> +            if (blank > 0) {
>> +                String authType = authHeader.substring(0, blank);
>> +                String authInfo = authHeader.substring(blank).trim();
>> +
>> +
>> +                if (authType.equalsIgnoreCase(AUTHENTICATION_SCHEME_BASIC)) {
>> +                    try {
>> +                        String srcString = base64Decode(authInfo);
>> +
>> +                        int i = srcString.indexOf(':');
>> +                        String username = srcString.substring(0, i);
>> +                        String password = srcString.substring(i + 1);
>> +
>> +                        // authenticate
>> +                        Subject subject = doAuthenticate(username, password);
>> +                        if (subject != null) {
>> +                            return true;
>> +                        }
>> +
>> +                    } catch (Exception e) {
>> +                        // Ignore
>> +                    }
>> +                }
>> +            }
>> +        }
>> +
>> +        // request authentication
>> +        try {
>> +            response.setHeader(HEADER_WWW_AUTHENTICATE, AUTHENTICATION_SCHEME_BASIC + " realm=\""
>> +                                                        + this.realm + "\"");
>> +            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
>> +            response.setContentLength(0);
>> +            response.flushBuffer();
>> +        } catch (IOException ioe) {
>> +            // failed sending the response ... cannot do anything about it
>> +        }
>> +
>> +        // inform HttpService that authentication failed
>> +        return false;
>> +    }
>> +
>> +    private static String base64Decode(String srcString) {
>> +        byte[] transformed = null;
>> +        try {
>> +            transformed = Base64Utility.decode(srcString);
>> +            return new String(transformed, "ISO-8859-1");
>> +        } catch (UnsupportedEncodingException uee) {
>> +            return srcString;
>> +        } catch (Base64Exception e) {
>> +            return srcString;
>> +        }
>> +    }
>> +
>> +}
>> 
>> Modified: cxf/trunk/rt/transports/http/src/main/resources/OSGI-INF/blueprint/osgiservlet.xml
>> URL: http://svn.apache.org/viewvc/cxf/trunk/rt/transports/http/src/main/resources/OSGI-INF/blueprint/osgiservlet.xml?rev=1507984&r1=1507983&r2=1507984&view=diff
>> ==============================================================================
>> --- cxf/trunk/rt/transports/http/src/main/resources/OSGI-INF/blueprint/osgiservlet.xml (original)
>> +++ cxf/trunk/rt/transports/http/src/main/resources/OSGI-INF/blueprint/osgiservlet.xml Mon Jul 29 09:31:48 2013
>> @@ -39,7 +39,8 @@ under the License.
>>        <cm:property name="org.apache.cxf.servlet.redirect-servlet-name" value=""/>
>>        <cm:property name="org.apache.cxf.servlet.redirect-servlet-path" value=""/>
>>        <cm:property name="org.apache.cxf.servlet.service-list-all-contexts" value=""/>
>> -
>> +      <cm:property name="org.apache.cxf.servlet.service-list-page-authenticate" value="false"/>
>> +      <cm:property name="org.apache.cxf.servlet.service-list-page-authenticate-realm" value="karaf"/>
>>      </cm:default-properties>
>> 
>>    </cm:property-placeholder>
>> @@ -64,6 +65,8 @@ under the License.
>>        <entry key="redirect-servlet-name" value="${org.apache.cxf.servlet.redirect-servlet-name}"/>
>>        <entry key="redirect-servlet-path" value="${org.apache.cxf.servlet.redirect-servlet-path}"/>
>>        <entry key="service-list-all-contexts" value="${org.apache.cxf.servlet.service-list-all-contexts}"/>
>> +      <entry key="service-list-page-authenticate" value="${org.apache.cxf.servlet.service-list-page-authenticate}"/>
>> +      <entry key="service-list-page-authenticate-realm" value="${org.apache.cxf.servlet.service-list-page-authenticate-realm}"/>
>>      </service-properties>
>>    </service>
>> 
>> 
>> 
> 
> 


Re: svn commit: r1507984 - in /cxf/trunk/rt/transports/http/src/main: java/org/apache/cxf/transport/servlet/ java/org/apache/cxf/transport/servlet/servicelist/ resources/OSGI-INF/blueprint/

Posted by Sergey Beryozkin <sb...@gmail.com>.
Hi Freeman

Can you please update ServiceListGeneratorServlet to actually remove the 
temp HTTPServletRequest attributes - because they are not needed any 
more after that ?

The reason is that these attributes will leak into JAX-RS 
ContainerRequestFilter.getProperties() - unfortunately this method has 
been tied to HTTPServletRequest attributes,

Thanks, Sergey

Thanks, Sergey
On 29/07/13 10:31, ffang@apache.org wrote:
> Author: ffang
> Date: Mon Jul 29 09:31:48 2013
> New Revision: 1507984
>
> URL: http://svn.apache.org/r1507984
> Log:
> [CXF-5165]add a JAAS authenticator for ServiceListPage
>
> Added:
>      cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListJAASAuthenticator.java
> Modified:
>      cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/ServletController.java
>      cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListGeneratorServlet.java
>      cxf/trunk/rt/transports/http/src/main/resources/OSGI-INF/blueprint/osgiservlet.xml
>
> Modified: cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/ServletController.java
> URL: http://svn.apache.org/viewvc/cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/ServletController.java?rev=1507984&r1=1507983&r2=1507984&view=diff
> ==============================================================================
> --- cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/ServletController.java (original)
> +++ cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/ServletController.java Mon Jul 29 09:31:48 2013
> @@ -40,12 +40,17 @@ import org.apache.cxf.transport.http.Abs
>   import org.apache.cxf.transport.http.DestinationRegistry;
>
>   public class ServletController {
> +
> +    public static final String AUTH_SERVICE_LIST = "auth.service.list";
> +    public static final String AUTH_SERVICE_LIST_REALM = "auth.service.list.realm";
>       protected static final String DEFAULT_LISTINGS_CLASSIFIER = "/services";
>       private static final Logger LOG = LogUtils.getL7dLogger(ServletController.class);
>       private static final String HTTP_PREFIX = "http";
> -
> +
>       protected boolean isHideServiceList;
> +    protected boolean isAuthServiceListPage;
>       protected boolean disableAddressUpdates;
> +    protected String authServiceListPageRealm;
>       protected String forcedBaseAddress;
>       protected String serviceListRelativePath = DEFAULT_LISTINGS_CLASSIFIER;
>       protected ServletConfig servletConfig;
> @@ -108,6 +113,17 @@ public class ServletController {
>           if (!StringUtils.isEmpty(hideServiceList)) {
>               this.isHideServiceList = Boolean.valueOf(hideServiceList);
>           }
> +
> +        String authServiceListPage = servletConfig.getInitParameter("service-list-page-authenticate");
> +        if (!StringUtils.isEmpty(authServiceListPage)) {
> +            this.isAuthServiceListPage = Boolean.valueOf(authServiceListPage);
> +        }
> +
> +        String authServiceListRealm = servletConfig.getInitParameter("service-list-page-authenticate-realm");
> +        if (!StringUtils.isEmpty(authServiceListRealm)) {
> +            this.authServiceListPageRealm = authServiceListRealm;
> +        }
> +
>           String isDisableAddressUpdates = servletConfig.getInitParameter("disable-address-updates");
>           if (!StringUtils.isEmpty(isDisableAddressUpdates)) {
>               this.disableAddressUpdates = Boolean.valueOf(isDisableAddressUpdates);
> @@ -143,6 +159,9 @@ public class ServletController {
>                       || request.getRequestURI().endsWith(serviceListRelativePath + "/")
>                       || StringUtils.isEmpty(pathInfo)
>                       || "/".equals(pathInfo))) {
> +                    if (isAuthServiceListPage) {
> +                        setAuthServiceListPageAttribute(request);
> +                    }
>                       setBaseURLAttribute(request);
>                       serviceListGenerator.service(request, res);
>                   } else {
> @@ -188,6 +207,12 @@ public class ServletController {
>           return true;
>       }
>
> +    private void setAuthServiceListPageAttribute(HttpServletRequest request) {
> +        request.setAttribute(ServletController.AUTH_SERVICE_LIST, this.isAuthServiceListPage);
> +        request.setAttribute(ServletController.AUTH_SERVICE_LIST_REALM, this.authServiceListPageRealm);
> +
> +    }
> +
>       public void invokeDestination(final HttpServletRequest request, HttpServletResponse response,
>                                     AbstractHTTPDestination d) throws ServletException {
>           if (LOG.isLoggable(Level.FINE)) {
>
> Modified: cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListGeneratorServlet.java
> URL: http://svn.apache.org/viewvc/cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListGeneratorServlet.java?rev=1507984&r1=1507983&r2=1507984&view=diff
> ==============================================================================
> --- cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListGeneratorServlet.java (original)
> +++ cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListGeneratorServlet.java Mon Jul 29 09:31:48 2013
> @@ -39,6 +39,7 @@ import org.apache.cxf.message.Message;
>   import org.apache.cxf.service.model.EndpointInfo;
>   import org.apache.cxf.transport.AbstractDestination;
>   import org.apache.cxf.transport.http.DestinationRegistry;
> +import org.apache.cxf.transport.servlet.ServletController;
>
>   public class ServiceListGeneratorServlet extends HttpServlet {
>       private static final long serialVersionUID = -113918058557537996L;
> @@ -67,6 +68,19 @@ public class ServiceListGeneratorServlet
>       @Override
>       public void service(HttpServletRequest request,
>                           HttpServletResponse response) throws ServletException, IOException {
> +        Object obj = request.getAttribute(ServletController.AUTH_SERVICE_LIST);
> +        boolean isAuthServiceList = false;
> +        if (obj != null) {
> +            isAuthServiceList = Boolean.valueOf(obj.toString());
> +        }
> +        if (isAuthServiceList) {
> +            String authServiceListRealm = (String)request.getAttribute(ServletController.AUTH_SERVICE_LIST_REALM);
> +            ServiceListJAASAuthenticator authenticator = new ServiceListJAASAuthenticator();
> +            authenticator.setRealm(authServiceListRealm);
> +            if (!authenticator.authenticate(request, response)) {
> +                return;
> +            }
> +        }
>           PrintWriter writer = response.getWriter();
>           AbstractDestination[] destinations = destinationRegistry.getSortedDestinations();
>           if (request.getParameter("stylesheet") != null) {
>
> Added: cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListJAASAuthenticator.java
> URL: http://svn.apache.org/viewvc/cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListJAASAuthenticator.java?rev=1507984&view=auto
> ==============================================================================
> --- cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListJAASAuthenticator.java (added)
> +++ cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/servlet/servicelist/ServiceListJAASAuthenticator.java Mon Jul 29 09:31:48 2013
> @@ -0,0 +1,163 @@
> +/**
> + * 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.cxf.transport.servlet.servicelist;
> +
> +import java.io.IOException;
> +import java.io.UnsupportedEncodingException;
> +import java.security.GeneralSecurityException;
> +import java.util.logging.Level;
> +import java.util.logging.Logger;
> +
> +import javax.security.auth.Subject;
> +import javax.security.auth.callback.Callback;
> +import javax.security.auth.callback.CallbackHandler;
> +import javax.security.auth.callback.NameCallback;
> +import javax.security.auth.callback.PasswordCallback;
> +import javax.security.auth.callback.UnsupportedCallbackException;
> +import javax.security.auth.login.AccountException;
> +import javax.security.auth.login.FailedLoginException;
> +import javax.security.auth.login.LoginContext;
> +import javax.servlet.http.HttpServletRequest;
> +import javax.servlet.http.HttpServletResponse;
> +
> +import org.apache.cxf.common.logging.LogUtils;
> +import org.apache.cxf.common.util.Base64Exception;
> +import org.apache.cxf.common.util.Base64Utility;
> +import org.apache.cxf.transport.http.blueprint.HttpDestinationBPBeanDefinitionParser;
> +
> +
> +
> +public class ServiceListJAASAuthenticator {
> +
> +    private static final Logger LOG = LogUtils.getL7dLogger(HttpDestinationBPBeanDefinitionParser.class);
> +
> +    private static final String HEADER_WWW_AUTHENTICATE = "WWW-Authenticate";
> +
> +    private static final String HEADER_AUTHORIZATION = "Authorization";
> +
> +    private static final String AUTHENTICATION_SCHEME_BASIC = "Basic";
> +
> +    private String realm;
> +
> +    public String getRealm() {
> +        return realm;
> +    }
> +
> +    public void setRealm(String realm) {
> +        this.realm = realm;
> +    }
> +
> +
> +    public Object authenticate(final String username, final String password) {
> +        return doAuthenticate(username, password);
> +    }
> +
> +    public Subject doAuthenticate(final String username, final String password) {
> +        try {
> +            Subject subject = new Subject();
> +            LoginContext loginContext = new LoginContext(realm, subject, new CallbackHandler() {
> +                public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
> +                    for (int i = 0; i < callbacks.length; i++) {
> +                        if (callbacks[i] instanceof NameCallback) {
> +                            ((NameCallback)callbacks[i]).setName(username);
> +                        } else if (callbacks[i] instanceof PasswordCallback) {
> +                            ((PasswordCallback)callbacks[i]).setPassword(password.toCharArray());
> +                        } else {
> +                            throw new UnsupportedCallbackException(callbacks[i]);
> +                        }
> +                    }
> +                }
> +            });
> +            loginContext.login();
> +            return subject;
> +        } catch (FailedLoginException e) {
> +            LOG.log(Level.FINE, "Login failed ", e);
> +            return null;
> +        } catch (AccountException e) {
> +            LOG.log(Level.WARNING, "Account failure ",  e);
> +            return null;
> +        } catch (GeneralSecurityException e) {
> +            LOG.log(Level.SEVERE, "General Security Exception ", e);
> +            return null;
> +        }
> +    }
> +
> +    public boolean authenticate(HttpServletRequest request, HttpServletResponse response) {
> +        // Return immediately if the header is missing
> +        String authHeader = request.getHeader(HEADER_AUTHORIZATION);
> +        if (authHeader != null && authHeader.length() > 0) {
> +
> +            // Get the authType (Basic, Digest) and authInfo (user/password)
> +            // from the header
> +            authHeader = authHeader.trim();
> +            int blank = authHeader.indexOf(' ');
> +            if (blank > 0) {
> +                String authType = authHeader.substring(0, blank);
> +                String authInfo = authHeader.substring(blank).trim();
> +
> +
> +                if (authType.equalsIgnoreCase(AUTHENTICATION_SCHEME_BASIC)) {
> +                    try {
> +                        String srcString = base64Decode(authInfo);
> +
> +                        int i = srcString.indexOf(':');
> +                        String username = srcString.substring(0, i);
> +                        String password = srcString.substring(i + 1);
> +
> +                        // authenticate
> +                        Subject subject = doAuthenticate(username, password);
> +                        if (subject != null) {
> +                            return true;
> +                        }
> +
> +                    } catch (Exception e) {
> +                        // Ignore
> +                    }
> +                }
> +            }
> +        }
> +
> +        // request authentication
> +        try {
> +            response.setHeader(HEADER_WWW_AUTHENTICATE, AUTHENTICATION_SCHEME_BASIC + " realm=\""
> +                                                        + this.realm + "\"");
> +            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
> +            response.setContentLength(0);
> +            response.flushBuffer();
> +        } catch (IOException ioe) {
> +            // failed sending the response ... cannot do anything about it
> +        }
> +
> +        // inform HttpService that authentication failed
> +        return false;
> +    }
> +
> +    private static String base64Decode(String srcString) {
> +        byte[] transformed = null;
> +        try {
> +            transformed = Base64Utility.decode(srcString);
> +            return new String(transformed, "ISO-8859-1");
> +        } catch (UnsupportedEncodingException uee) {
> +            return srcString;
> +        } catch (Base64Exception e) {
> +            return srcString;
> +        }
> +    }
> +
> +}
>
> Modified: cxf/trunk/rt/transports/http/src/main/resources/OSGI-INF/blueprint/osgiservlet.xml
> URL: http://svn.apache.org/viewvc/cxf/trunk/rt/transports/http/src/main/resources/OSGI-INF/blueprint/osgiservlet.xml?rev=1507984&r1=1507983&r2=1507984&view=diff
> ==============================================================================
> --- cxf/trunk/rt/transports/http/src/main/resources/OSGI-INF/blueprint/osgiservlet.xml (original)
> +++ cxf/trunk/rt/transports/http/src/main/resources/OSGI-INF/blueprint/osgiservlet.xml Mon Jul 29 09:31:48 2013
> @@ -39,7 +39,8 @@ under the License.
>         <cm:property name="org.apache.cxf.servlet.redirect-servlet-name" value=""/>
>         <cm:property name="org.apache.cxf.servlet.redirect-servlet-path" value=""/>
>         <cm:property name="org.apache.cxf.servlet.service-list-all-contexts" value=""/>
> -
> +      <cm:property name="org.apache.cxf.servlet.service-list-page-authenticate" value="false"/>
> +      <cm:property name="org.apache.cxf.servlet.service-list-page-authenticate-realm" value="karaf"/>
>       </cm:default-properties>
>
>     </cm:property-placeholder>
> @@ -64,6 +65,8 @@ under the License.
>         <entry key="redirect-servlet-name" value="${org.apache.cxf.servlet.redirect-servlet-name}"/>
>         <entry key="redirect-servlet-path" value="${org.apache.cxf.servlet.redirect-servlet-path}"/>
>         <entry key="service-list-all-contexts" value="${org.apache.cxf.servlet.service-list-all-contexts}"/>
> +      <entry key="service-list-page-authenticate" value="${org.apache.cxf.servlet.service-list-page-authenticate}"/>
> +      <entry key="service-list-page-authenticate-realm" value="${org.apache.cxf.servlet.service-list-page-authenticate-realm}"/>
>       </service-properties>
>     </service>
>
>
>