You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by ch...@apache.org on 2011/12/24 14:32:59 UTC

svn commit: r1222972 - in /activemq/activemq-apollo/trunk: apollo-broker/src/main/scala/org/apache/activemq/apollo/broker/security/ apollo-stomp/src/main/scala/org/apache/activemq/apollo/stomp/ apollo-web/src/main/scala/org/apache/activemq/apollo/web/r...

Author: chirino
Date: Sat Dec 24 13:32:59 2011
New Revision: 1222972

URL: http://svn.apache.org/viewvc?rev=1222972&view=rev
Log:
Fixes APLO-124 : Call the LoginModule.logout method when the user no longer has an active session against the server.

Added:
    activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/UserInfo.scala
Modified:
    activemq/activemq-apollo/trunk/apollo-broker/src/main/scala/org/apache/activemq/apollo/broker/security/JaasAuthenticator.scala
    activemq/activemq-apollo/trunk/apollo-broker/src/main/scala/org/apache/activemq/apollo/broker/security/SecurityContext.scala
    activemq/activemq-apollo/trunk/apollo-stomp/src/main/scala/org/apache/activemq/apollo/stomp/StompProtocolHandler.scala
    activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/BrokerResource.scala
    activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/Support.scala

Modified: activemq/activemq-apollo/trunk/apollo-broker/src/main/scala/org/apache/activemq/apollo/broker/security/JaasAuthenticator.scala
URL: http://svn.apache.org/viewvc/activemq/activemq-apollo/trunk/apollo-broker/src/main/scala/org/apache/activemq/apollo/broker/security/JaasAuthenticator.scala?rev=1222972&r1=1222971&r2=1222972&view=diff
==============================================================================
--- activemq/activemq-apollo/trunk/apollo-broker/src/main/scala/org/apache/activemq/apollo/broker/security/JaasAuthenticator.scala (original)
+++ activemq/activemq-apollo/trunk/apollo-broker/src/main/scala/org/apache/activemq/apollo/broker/security/JaasAuthenticator.scala Sat Dec 24 13:32:59 2011
@@ -106,6 +106,7 @@ class JaasAuthenticator(val config: Auth
       true
     } catch {
       case x: Exception =>
+        security_ctx.login_context = null
         log.info("authentication failed: local:%s, remote:%s, reason:%s ", security_ctx.local_address, security_ctx.remote_address, x.getMessage)
         false
     } finally {

Modified: activemq/activemq-apollo/trunk/apollo-broker/src/main/scala/org/apache/activemq/apollo/broker/security/SecurityContext.scala
URL: http://svn.apache.org/viewvc/activemq/activemq-apollo/trunk/apollo-broker/src/main/scala/org/apache/activemq/apollo/broker/security/SecurityContext.scala?rev=1222972&r1=1222971&r2=1222972&view=diff
==============================================================================
--- activemq/activemq-apollo/trunk/apollo-broker/src/main/scala/org/apache/activemq/apollo/broker/security/SecurityContext.scala (original)
+++ activemq/activemq-apollo/trunk/apollo-broker/src/main/scala/org/apache/activemq/apollo/broker/security/SecurityContext.scala Sat Dec 24 13:32:59 2011
@@ -17,13 +17,12 @@
 package org.apache.activemq.apollo.broker.security
 
 import java.security.Principal
-import collection.mutable.HashSet
 import javax.security.auth.Subject
 import java.security.cert.X509Certificate
-import org.apache.activemq.apollo.util.OptionSupport._
-import org.apache.activemq.jaas.{GroupPrincipal, UserPrincipal}
-import javax.security.auth.login.LoginContext
 import java.net.SocketAddress
+import org.apache.activemq.apollo.broker.Broker.BLOCKABLE_THREAD_POOL
+import org.fusesource.hawtdispatch._
+import javax.security.auth.login.LoginContext
 
 /**
  * <p>
@@ -35,6 +34,7 @@ class SecurityContext {
 
   var user:String = _
   var password:String = _
+  var sso_token:String = _
   var certificates:Array[X509Certificate] = _
   var local_address:SocketAddress = _
   var remote_address:SocketAddress = _
@@ -91,4 +91,26 @@ class SecurityContext {
     }
   }
 
+  /**
+   * Logs the user off, called func when completed. Pass
+   * any errors that occurred during the log off process
+   * to the function or null.
+   */
+  def logout(func: (Throwable)=>Unit) = {
+    if(login_context==null) {
+      func(null)
+    } else {
+      val lc = login_context
+      login_context = null
+      BLOCKABLE_THREAD_POOL {
+        try {
+          lc.logout()
+          func(null)
+        } catch {
+          case e:Throwable => func(e)
+        }
+      }
+    }
+  }
+  
 }
\ No newline at end of file

Modified: activemq/activemq-apollo/trunk/apollo-stomp/src/main/scala/org/apache/activemq/apollo/stomp/StompProtocolHandler.scala
URL: http://svn.apache.org/viewvc/activemq/activemq-apollo/trunk/apollo-stomp/src/main/scala/org/apache/activemq/apollo/stomp/StompProtocolHandler.scala?rev=1222972&r1=1222971&r2=1222972&view=diff
==============================================================================
--- activemq/activemq-apollo/trunk/apollo-stomp/src/main/scala/org/apache/activemq/apollo/stomp/StompProtocolHandler.scala (original)
+++ activemq/activemq-apollo/trunk/apollo-stomp/src/main/scala/org/apache/activemq/apollo/stomp/StompProtocolHandler.scala Sat Dec 24 13:32:59 2011
@@ -699,6 +699,11 @@ class StompProtocolHandler extends Proto
           host.router.unbind(consumer.destination, consumer, false , security_context)
       }
       consumers = Map()
+      security_context.logout( e => {
+        if(e!=null) {
+          connection_log.info(e, "STOMP connection '%s' log out error: %s", security_context.remote_address, e.toString)
+        }
+      })
       trace("stomp protocol resources released")
     }
   }

Modified: activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/BrokerResource.scala
URL: http://svn.apache.org/viewvc/activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/BrokerResource.scala?rev=1222972&r1=1222971&r2=1222972&view=diff
==============================================================================
--- activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/BrokerResource.scala (original)
+++ activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/BrokerResource.scala Sat Dec 24 13:32:59 2011
@@ -36,6 +36,7 @@ import org.apache.activemq.apollo.broker
 import java.security.Principal
 import org.apache.activemq.apollo.dto._
 import javax.ws.rs.core.MediaType._
+import security.SecurityContext
 
 /**
  * <p>
@@ -71,37 +72,59 @@ case class BrokerResource() extends Reso
     new ArrayList[PrincipalDTO](rc.map(x=>new PrincipalDTO(x.getClass.getName, x.getName)))
   }
 
+  @Produces(Array("text/html;qs=5"))
   @GET
   @Path("signin")
-  def get_signin(@Context response:HttpServletResponse, @QueryParam("username") username:String, @QueryParam("password") password:String):Boolean = {
-    post_signin(response, username, password)
+  def get_signin_html(@Context response:HttpServletResponse, @QueryParam("username") username:String, @QueryParam("password") password:String): ErrorDTO = {
+    if(post_signin(response, username, password)) {
+      result(strip_resolve("../.."))
+    } else {
+      var dto = new ErrorDTO()
+      dto.code = "%d: %s".format(BAD_REQUEST.getStatusCode, BAD_REQUEST.getReasonPhrase)
+      dto.message = "Invalid user id or password";
+      result(BAD_REQUEST, dto)
+    }
   }
 
+//  @GET
+//  @Path("signin")
+//  def get_signin(@Context response:HttpServletResponse, @QueryParam("username") username:String, @QueryParam("password") password:String):Boolean = {
+//    post_signin(response, username, password)
+//  }
+
   @POST
   @Path("signin")
   def post_signin(@Context response:HttpServletResponse, @FormParam("username") username:String, @FormParam("password") password:String):Boolean =  {
     try {
-      http_request.setAttribute("username", username)
-      http_request.setAttribute("password", password)
+      val user_info = UserInfo(username, password)
+      http_request.setAttribute("user_info", user_info)
       unwrap_future_result[Boolean] {
         with_broker { broker =>
           monitoring(broker) {
             // Only create the session if he is a valid user.
             val session = http_request.getSession(true)
-            session.setAttribute("username", username)
-            session.setAttribute("password", password)
+            user_info.security_context = http_request.getAttribute(SECURITY_CONTEXT_ATTRIBUTE).asInstanceOf[SecurityContext]
+            session.setAttribute("user_info", user_info)
             true
           }
         }
       }
     } catch {
       case e:WebApplicationException => // this happens if user is not authorized
+        e.printStackTrace()
         false
     }
   }
 
-  @GET
-  @Path("signout")
+  @Produces(Array("text/html"))
+  @GET @Path("signout")
+  def signout_html():Unit = {
+    signout()
+    result(strip_resolve("../.."))
+  }
+
+  @Produces(Array(APPLICATION_JSON, APPLICATION_XML, TEXT_XML))
+  @GET @Path("signout")
   def signout():Unit =  {
     val session = http_request.getSession(false)
     if( session !=null ) {
@@ -480,7 +503,7 @@ case class BrokerResource() extends Reso
       Success(rc)
     } catch {
       case e:Throwable =>
-        Failure(create_result(BAD_REQUEST, new ErrorDTO(e.getMessage)))
+        Failure(create_result(BAD_REQUEST, e.getMessage))
     }
   }
 

Modified: activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/Support.scala
URL: http://svn.apache.org/viewvc/activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/Support.scala?rev=1222972&r1=1222971&r2=1222972&view=diff
==============================================================================
--- activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/Support.scala (original)
+++ activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/Support.scala Sat Dec 24 13:32:59 2011
@@ -161,21 +161,37 @@ abstract class Resource(parent:Resource=
   protected def authenticate[T](authenticator:Authenticator)(func: (SecurityContext)=>Unit): Unit = {
 
     var security_context = http_request.getAttribute(SECURITY_CONTEXT_ATTRIBUTE).asInstanceOf[SecurityContext]
+    if(security_context == null) {
+      // perhaps we can find it in the session
+      var session = http_request.getSession(false)
+      if( session!=null ) {
+        var user_info = session.getAttribute("user_info").asInstanceOf[UserInfo];
+        if( user_info!=null ) {
+          security_context = user_info.security_context;
+        }
+      }
+    }
+
     if( security_context!=null ) {
+      // yay.. user is already logged in.
       func(security_context)
     } else {
+
       security_context = new SecurityContext
       security_context.local_address = new InetSocketAddress(http_request.getLocalAddr, http_request.getLocalPort)
       security_context.remote_address = new InetSocketAddress(http_request.getRemoteAddr, http_request.getRemotePort)
       security_context.certificates = http_request.getAttribute("javax.servlet.request.X509Certificate").asInstanceOf[Array[X509Certificate]]
 
-      if(http_request.getAttribute("username")!=null) {
-        security_context.user = http_request.getAttribute("username").asInstanceOf[String];
-        security_context.password = http_request.getAttribute("password").asInstanceOf[String];
-      } else if( http_request.getSession(false) !=null ) {
+      var user_info = http_request.getAttribute("user_info").asInstanceOf[UserInfo];
+      if( user_info==null  ) {
         val session = http_request.getSession(false)
-        security_context.user = session.getAttribute("username").asInstanceOf[String];
-        security_context.password = session.getAttribute("password").asInstanceOf[String];
+        if( session!=null ) {
+          user_info = session.asInstanceOf[UserInfo];
+        }
+      }
+      if(user_info!=null) {
+        security_context.user = user_info.username
+        security_context.password = user_info.password
       } else {
         var auth_header = http_request.getHeader(HEADER_AUTHORIZATION)
         if (auth_header != null && auth_header.length > 0) {
@@ -207,10 +223,23 @@ abstract class Resource(parent:Resource=
           }
         }
       }
+
+      def call_func_with_security = {
+        http_request.setAttribute(SECURITY_CONTEXT_ATTRIBUTE, security_context)
+        try {
+          func(security_context)
+        } finally {
+          // If there is no session, then we have to logout at the end of the request.
+          if( http_request.getSession(false)==null ) {
+            security_context.logout((error)=>{
+            })
+          }
+        }
+      }
+
       reset {
         if( authenticator.authenticate(security_context) ) {
-          http_request.setAttribute(SECURITY_CONTEXT_ATTRIBUTE, security_context)
-          func(security_context)
+          call_func_with_security
         } else {
           func(null)
         }

Added: activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/UserInfo.scala
URL: http://svn.apache.org/viewvc/activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/UserInfo.scala?rev=1222972&view=auto
==============================================================================
--- activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/UserInfo.scala (added)
+++ activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/UserInfo.scala Sat Dec 24 13:32:59 2011
@@ -0,0 +1,49 @@
+/**
+ * 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.activemq.apollo.web.resources
+
+import org.apache.activemq.apollo.broker.security.SecurityContext
+import javax.servlet.http._
+import java.util.concurrent.CountDownLatch
+
+case class UserInfo(username:String, password:String) extends HttpSessionActivationListener with HttpSessionBindingListener {
+
+  //
+  // We hold on to the security_context so we can log the user out of the JAAS login module.
+  // If the session is passivated, expired, or deleted, we automatically log the user
+  // out of the JAAS login module.
+  //
+  @transient
+  var security_context: SecurityContext = null
+  
+  def logout = {
+    if(security_context!=null ) {
+      val cd = new CountDownLatch(1)
+      security_context.logout((e)=> {
+        // ignore for now..
+        cd.countDown();
+      })
+      security_context = null
+      cd.await();
+    }
+  }
+
+  def valueBound(event: HttpSessionBindingEvent) {}
+  def valueUnbound(event: HttpSessionBindingEvent) = logout
+  def sessionDidActivate(se: HttpSessionEvent) {}
+  def sessionWillPassivate(se: HttpSessionEvent) = logout
+}