--- a/src/main/scala/ReadWriteWebMain.scala Fri Oct 21 23:01:04 2011 +0200
+++ b/src/main/scala/ReadWriteWebMain.scala Sat Oct 22 15:56:21 2011 +0200
@@ -10,11 +10,12 @@
import org.clapper.argot._
import ArgotConverters._
-import javax.servlet.http.HttpServletRequest
import unfiltered.request.HttpRequest
+import unfiltered.Cycle
+import javax.servlet.http.{HttpServletResponse, HttpServletRequest}
+import unfiltered.filter.Plan
-object ReadWriteWebMain {
-
+trait ReadWriteWebArgs {
val logger: Logger = LoggerFactory.getLogger(this.getClass)
val postUsageMsg= Some("""
@@ -69,6 +70,14 @@
val baseURL = parser.parameter[String]("baseURL", "base URL", false)
+}
+
+
+object ReadWriteWebMain extends ReadWriteWebArgs {
+
+ implicit def planify(intent: Plan.Intent): unfiltered.filter.Plan =
+ unfiltered.filter.Planify(intent)
+
// regular Java main
def main(args: Array[String]) {
@@ -98,7 +107,7 @@
ctx.resources(ClasspathUtils.fromClasspath("public/").toURI.toURL)
}.
filter(app.plan).
- filter(new X509view().plan).
+ filter(new X509view().intent[HttpServletRequest,HttpServletResponse]).
filter(new EchoPlan().plan).run()
}
--- a/src/main/scala/auth/X509Cert.scala Fri Oct 21 23:01:04 2011 +0200
+++ b/src/main/scala/auth/X509Cert.scala Sat Oct 22 15:56:21 2011 +0200
@@ -24,19 +24,62 @@
package org.w3.readwriteweb.auth
import javax.servlet.http.HttpServletRequest
-import java.security.cert.X509Certificate
import unfiltered.request.HttpRequest
+import unfiltered.netty.ReceivedMessage
+import java.security.cert.{X509Certificate}
+import java.security.cert.Certificate
-/**
- * @author Henry Story, with help from Doug Tangren on unfiltered mailing list
- * @created: 14/10/2011
- */
-object X509Cert {
- def unapply[T <: HttpServletRequest](r: HttpRequest[T]): Option[Array[X509Certificate]] =
- r.underlying.getAttribute("javax.servlet.request.X509Certificate") match {
- case certs: Array[X509Certificate] => Some(certs)
- case _ => None
+object Certs {
+
+
+ def unapplySeq[T](r: HttpRequest[T]) (implicit m: Manifest[T]) : Option[IndexedSeq[Certificate]] = {
+ if (m <:< manifest[HttpServletRequest]) unapplyServletRequest(r.asInstanceOf[HttpRequest[HttpServletRequest]])
+ else if (m <:< manifest[ReceivedMessage]) unapplyReceivedMessage(r.asInstanceOf[HttpRequest[ReceivedMessage]])
+ else None //todo: should perhaps throw an exception here.
}
-}
\ No newline at end of file
+
+ //todo: both of these return X509Certificates optionally.
+ //todo: but they don't pass any error messages along, which they could in the case of netty
+
+ private def unapplyServletRequest[T <: HttpServletRequest](r: HttpRequest[T]):
+ Option[IndexedSeq[Certificate]] = {
+ r.underlying.getAttribute("javax.servlet.request.X509Certificate") match {
+ case certs: Array[Certificate] => Some(certs)
+ case _ => None
+ }
+ }
+
+ private def unapplyReceivedMessage[T <: ReceivedMessage](r: HttpRequest[T]):
+ Option[IndexedSeq[Certificate]] = {
+
+ import org.jboss.netty.handler.ssl.SslHandler
+ r.underlying.context.getPipeline.get(classOf[SslHandler]) match {
+ case sslh: SslHandler => {
+ sslh.setEnableRenegotiation(true)
+ sslh.getEngine.setWantClientAuth(true)
+ val future = sslh.handshake()
+ future.await(30000) //that's certainly way too long.
+ if (future.isDone) {
+ if (future.isSuccess)
+ try {
+ Some(sslh.getEngine.getSession.getPeerCertificates)
+ } catch {
+ case e => None
+ }
+ else {
+ None
+ }
+
+ } else {
+ None
+ }
+ }
+ case _ => None
+ }
+
+ }
+
+}
+
--- a/src/main/scala/auth/X509Claim.scala Fri Oct 21 23:01:04 2011 +0200
+++ b/src/main/scala/auth/X509Claim.scala Sat Oct 22 15:56:21 2011 +0200
@@ -50,9 +50,9 @@
def load(x509: X509Certificate) = new X509Claim(x509)
})
- def unapply[T <: HttpServletRequest](r: HttpRequest[T])(implicit webCache: WebCache): Option[X509Claim] =
+ def unapply[T](r: HttpRequest[T])(implicit webCache: WebCache,m: Manifest[T]): Option[X509Claim] =
r match {
- case X509Cert(certs) => Some(idCache.get(certs(0)))
+ case Certs(c1: X509Certificate, _*) => Some(idCache.get(c1))
case _ => None
}
--- a/src/main/scala/auth/X509view.scala Fri Oct 21 23:01:04 2011 +0200
+++ b/src/main/scala/auth/X509view.scala Sat Oct 22 15:56:21 2011 +0200
@@ -26,6 +26,7 @@
import unfiltered.request.Path
import unfiltered.response.{Html, ContentType, Ok}
import org.w3.readwriteweb.WebCache
+import unfiltered.Cycle
/**
* This plan just described the X509 WebID authentication information.
@@ -35,14 +36,14 @@
* @created: 13/10/2011
*/
-class X509view(implicit val webCache: WebCache) {
+class X509view()(implicit val webCache: WebCache) {
- val plan = unfiltered.filter.Planify {
+ def intent[A: Manifest,B]: Cycle.Intent[A, B] = {
case req @ Path(path) if path startsWith "/test/auth/x509" =>
Ok ~> ContentType("text/html") ~> Html(
<html><head><title>Authentication Page</title></head>
{ req match {
- case X509Claim(xclaim: X509Claim) => <body>
+ case X509Claim(xclaim) => <body>
<h1>Authentication Info received</h1>
<p>You were identified with the following WebIDs</p>
<ul>{xclaim.webidclaims.filter(cl=>cl.verified).map(p=> <li>{p.webId}</li>)}</ul>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/netty/ReadWriteWebNetty.scala Sat Oct 22 15:56:21 2011 +0200
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2011 Henry Story (bblfish.net)
+ * under the MIT licence defined
+ * http://www.opensource.org/licenses/mit-license.html
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in the
+ * Software without restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the
+ * following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package org.w3.readwriteweb.netty
+
+import org.clapper.argot.ArgotUsageException
+import scala.Console._
+import org.w3.readwriteweb.auth.{X509view, RDFAuthZ}
+import org.w3.readwriteweb._
+import unfiltered.netty.{ServerErrorResponse, cycle}
+
+/**
+ * ReadWrite Web for Netty server, allowing content renegotiation
+ *
+ * @author hjs
+ * @created: 21/10/2011
+ */
+
+class ReadWriteWebNetty extends ReadWriteWebArgs {
+
+ // regular Java main
+ def main(args: Array[String]) {
+
+ try {
+ parser.parse(args)
+ } catch {
+ case e: ArgotUsageException => err.println(e.message); sys.exit(1)
+ }
+
+ val filesystem =
+ new Filesystem(
+ rootDirectory.value.get,
+ baseURL.value.get,
+ lang=rdfLanguage.value getOrElse RDFXML)(mode.value getOrElse ResourcesDontExistByDefault)
+
+ val app = new ReadWriteWeb(filesystem, new RDFAuthZ(webCache,filesystem))
+
+ //this is incomplete: we should be able to start both ports.... not sure how to do this yet.
+ val service = httpsPort.value match {
+ case Some(port) => new KeyAuth_Https(port)
+ case None => new KeyAuth_Https(httpPort.value.get)
+ }
+
+ // configures and launches a Netty server
+ service.plan( new tmp ).run()
+
+ }
+
+ class tmp extends cycle.Plan with ServerErrorResponse
+}
\ No newline at end of file