initial commit
This commit is contained in:
commit
ed1db8803f
|
@ -0,0 +1,21 @@
|
|||
finagle-native/lib/finaglenative.jar
|
||||
target/
|
||||
dist/
|
||||
project/boot/
|
||||
project/plugins/project/
|
||||
project/plugins/src_managed/
|
||||
*.log
|
||||
*.tmproj
|
||||
lib_managed/
|
||||
*.swp
|
||||
*.iml
|
||||
out/
|
||||
.ensime
|
||||
*~
|
||||
*#
|
||||
.#*
|
||||
.ivyjars
|
||||
.idea
|
||||
.DS_Store
|
||||
sbt-launch-0.7.5.jar
|
||||
sbt-launch.jar
|
|
@ -0,0 +1,17 @@
|
|||
language: scala
|
||||
|
||||
scala:
|
||||
- 2.11.1
|
||||
|
||||
jdk:
|
||||
- oraclejdk7
|
||||
- openjdk6
|
||||
- openjdk7
|
||||
|
||||
before_script:
|
||||
# default $SBT_OPTS is irrelevant to sbt lancher
|
||||
- unset SBT_OPTS
|
||||
|
||||
script:
|
||||
# run for all environments
|
||||
- ./sbt ++$TRAVIS_SCALA_VERSION borderpatrol-core/test
|
|
@ -0,0 +1,57 @@
|
|||
How to Contribute to BorderPatrol
|
||||
=================================
|
||||
|
||||
Thanks for your interest in the BorderPatrol project. When you make a
|
||||
contribution to the project (e.g. any modifications, additions to existing
|
||||
work, pull requests or any other work intentionally submitted by you for
|
||||
inclusion in the project) (collectively, a "Contribution"), Lookout wants to be
|
||||
able to use your Contribution to improve this project and other Lookout
|
||||
products.
|
||||
|
||||
As a condition of providing a Contribution, you agree to the following terms
|
||||
and conditions ("Terms"):
|
||||
|
||||
1. Copyright License: Subject to these Terms, you grant Lookout and to
|
||||
recipients of software distributed by Lookout a perpetual, worldwide,
|
||||
non-exclusive, no-charge, royalty-free, irrevocable license to make, use, sell,
|
||||
reproduce, modify, distribute (directly and indirectly), and publicly display
|
||||
and perform the Contribution, and any derivative works that Lookout may make
|
||||
from the Contribution.
|
||||
|
||||
2. Patent License: Subject to these Terms, you grant Lookout and to
|
||||
recipients of software distributed by Lookout a perpetual, worldwide,
|
||||
non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this
|
||||
section) patent license to make, have made, use, offer to sell, sell, import,
|
||||
or otherwise transfer the Contribution, where such license applies only to
|
||||
those patent claims licensable by you that are necessarily infringed by your
|
||||
Contribution(s) alone or by combination of your Contribution(s) with any works
|
||||
or projects to which such Contribution(s) was submitted. If any entity
|
||||
institutes patent litigation against you or any other entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that your Contribution(s) or
|
||||
the projects to which you have contributed, constitutes direct or contributory
|
||||
patent infringement, then any patent licenses granted to that entity under this
|
||||
agreement for that Contribution, work or other project shall terminate as of
|
||||
the date such litigation is filed.
|
||||
|
||||
3. You warrant and represent that the Contribution(s) is your original
|
||||
creation, that you have the authority and are legally entitled to grant these
|
||||
licenses to Lookout, and that these licenses do not require the permission of
|
||||
any third party.
|
||||
|
||||
4. Except for the warranties in Section 3, you provide any Contribution(s) on
|
||||
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
or implied, including, without limitation, any warranties or conditions of
|
||||
TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
5. You agree to notify Lookout of any facts or circumstances of which you
|
||||
become aware of that would make any representations made by you inaccurate in
|
||||
any respect.
|
||||
|
||||
|
||||
Should you wish to submit a suggestion or work that is not your original
|
||||
creation, you may submit it to Lookout separate from any Contribution,
|
||||
explicitly identifying it as sourced from a third party, stating the complete
|
||||
details of its source, and informing Lookout of any license or other
|
||||
restriction (including but not limited to related patents, trademarks, and
|
||||
license agreement) of which you are personally aware, and conspicuously marking
|
||||
the work as "Submitted on behalf of a third party: [named here]."
|
|
@ -0,0 +1,22 @@
|
|||
Copyright (c) 2014 Lookout, Inc.
|
||||
|
||||
MIT License
|
||||
|
||||
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.
|
|
@ -0,0 +1,35 @@
|
|||
# BorderPatrol
|
||||
|
||||
BorderPatrol is an authentication and session management service that
|
||||
lives at the border of your network.
|
||||
|
||||
This version is a port from nginx+lua to finagle. For more information see
|
||||
[ngx_borderpatrol](https://www.github.com/lookout/ngx_borderpatrol)
|
||||
|
||||
## Developing/Contributing
|
||||
|
||||
### Installation and running
|
||||
|
||||
Border Patrol is based on TwitterServer and all dependencies are managed by SBT
|
||||
(Maven may or may not work and is experimental).
|
||||
|
||||
On OSX:
|
||||
|
||||
* brew install sbt
|
||||
* cd borderpatrol
|
||||
* ./sbt
|
||||
* project borderpatrol-core
|
||||
* run
|
||||
|
||||
This will get you a dumb little prototype responding differently to /b and /d routes
|
||||
|
||||
### IRC
|
||||
|
||||
Join `#borderpatrol` on the [Freenode](http://freenode.net)
|
||||
|
||||
## TODO
|
||||
|
||||
* Fix Maven builds
|
||||
* Implement Auth Token client
|
||||
* Routing
|
||||
* much, much more
|
|
@ -0,0 +1,14 @@
|
|||
maven_layout()
|
||||
|
||||
jar_library(name='borderpatrol-core',
|
||||
dependencies=[
|
||||
pants('borderpatrol/borderpatrol-core/src/main/scala')
|
||||
]
|
||||
)
|
||||
|
||||
jar_library(name='tests',
|
||||
dependencies=[
|
||||
pants('borderpatrol/borderpatrol-core/src/test/java'),
|
||||
pants('borderpatrol/borderpatrol-core/src/test/scala')
|
||||
]
|
||||
)
|
|
@ -0,0 +1,74 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.lookout</groupId>
|
||||
<artifactId>borderpatrol-core</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>scala-tools.org</id>
|
||||
<name>Scala-tools Maven2 Repository</name>
|
||||
<url>http://scala-tools.org/repo-releases</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>twitter</id>
|
||||
<url>http://maven.twttr.com/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>mvnrepository</id>
|
||||
<url>http://mvnrepository.com/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>scala-tools.org</id>
|
||||
<name>Scala-tools Maven2 Repository</name>
|
||||
<url>http://scala-tools.org/repo-releases</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.twitter</groupId>
|
||||
<artifactId>twitter-server_2.9.2</artifactId>
|
||||
<version>1.0.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.scalatest</groupId>
|
||||
<artifactId>scalatest_2.11</artifactId>
|
||||
<version>2.2.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<sourceDirectory>src/main/scala</sourceDirectory>
|
||||
<testSourceDirectory>src/test/scala</testSourceDirectory>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.scala-tools</groupId>
|
||||
<artifactId>maven-scala-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
<goal>testCompile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<sourceDir>src/main/java</sourceDir>
|
||||
<jvmArgs>
|
||||
<jvmArg>-Xms64m</jvmArg>
|
||||
<jvmArg>-Xmx1024m</jvmArg>
|
||||
</jvmArgs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -0,0 +1,7 @@
|
|||
scala_library(name='scala',
|
||||
dependencies=[
|
||||
pants('3rdparty:netty'),
|
||||
pants('3rdparty:finagle'),
|
||||
],
|
||||
sources=rglobs('*.scala'),
|
||||
)
|
|
@ -0,0 +1,69 @@
|
|||
package com.lookout.borderpatrol
|
||||
|
||||
import java.net.InetSocketAddress
|
||||
|
||||
import com.lookout.borderpatrol.routing._
|
||||
import com.lookout.borderpatrol.auth._
|
||||
import com.lookout.borderpatrol.sessions._
|
||||
import com.twitter.finagle.{Filter, _}
|
||||
import com.twitter.finagle.builder.{ClientBuilder, Server, ServerBuilder}
|
||||
import com.twitter.finagle.http.Http
|
||||
import com.twitter.server.TwitterServer
|
||||
import com.twitter.util._
|
||||
import org.jboss.netty.handler.codec.http._
|
||||
|
||||
object BorderPatrolApp extends TwitterServer {
|
||||
|
||||
val sessionStore = new SessionStore
|
||||
|
||||
val sessionIDFilter = new SessionIDFilter(sessionStore)
|
||||
val routingFilter = new RoutingFilter
|
||||
val sessionStoreFilter = new SessionStoreFilter(sessionStore)
|
||||
val authFilter = new AuthFilter
|
||||
val authService = new AuthService
|
||||
|
||||
val orchestratorFilter: Filter[HttpRequest, HttpResponse, HttpRequest, HttpResponse] =
|
||||
sessionIDFilter andThen routingFilter andThen sessionStoreFilter andThen authFilter
|
||||
|
||||
|
||||
val service = new Service[HttpRequest, HttpResponse] {
|
||||
def apply(request: HttpRequest) = {
|
||||
log.info("Service: Received a request at " + Time.now + ". Calling upstream =" + request.getUri())
|
||||
|
||||
val newUri = request.getUri.split("/").toSeq match {
|
||||
case Seq() => "/"
|
||||
case x => x.tail.tail.mkString("/", "/", "")
|
||||
}
|
||||
|
||||
log.info("new uri: " + newUri)
|
||||
request.setUri(newUri)
|
||||
//call upstream
|
||||
val client: Service[HttpRequest, HttpResponse] = ClientBuilder()
|
||||
.codec(Http())
|
||||
.hosts(request.getHeader("HOST")) // If >1 host, client does simple load-balancing
|
||||
.hostConnectionLimit(1)
|
||||
.build()
|
||||
|
||||
val clientWithTokenFilter = new TokenFilter(sessionStore) andThen client
|
||||
|
||||
clientWithTokenFilter(request)
|
||||
}
|
||||
}
|
||||
|
||||
val orchestratorService: Service[HttpRequest, HttpResponse] =
|
||||
orchestratorFilter andThen service
|
||||
|
||||
def main() {
|
||||
|
||||
val myService: Service[HttpRequest, HttpResponse] = sessionIDFilter andThen routingFilter andThen service
|
||||
//HttpMuxer.addHandler("/b", orchestratorService)
|
||||
// And wait on the server
|
||||
val server: Server = ServerBuilder()
|
||||
.codec(Http())
|
||||
.bindTo(new InetSocketAddress(8081))
|
||||
.name("lbutt")
|
||||
.build(orchestratorService)
|
||||
//val server = Http.serve(":8080", myService)
|
||||
//Await.ready(httpServer)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package com.lookout.borderpatrol.auth
|
||||
|
||||
import org.jboss.netty.buffer._
|
||||
import org.jboss.netty.handler.codec.http.{HttpRequest, HttpResponse, HttpResponseStatus}
|
||||
import com.twitter.finagle.{SimpleFilter, Service}
|
||||
import org.jboss.netty.buffer.ChannelBuffers.copiedBuffer
|
||||
import org.jboss.netty.util.CharsetUtil.UTF_8
|
||||
|
||||
/**
|
||||
* Transforms an upstream responses 401 UNAUTHORIZED into a 301 Redirect to Checkpoint
|
||||
*
|
||||
* Created by akuhnhausen on 6/11/14.
|
||||
*/
|
||||
class AuthFilter extends SimpleFilter[HttpRequest, HttpResponse] {
|
||||
def apply(request: HttpRequest, service: Service[HttpRequest, HttpResponse]) = {
|
||||
|
||||
// When the upstream have us a 401, transform it to a 302 and return the auth URL.
|
||||
service(request).onSuccess(resp => {
|
||||
if(resp.getStatus == HttpResponseStatus.UNAUTHORIZED) {
|
||||
resp.setStatus(HttpResponseStatus.MOVED_PERMANENTLY)
|
||||
// TODO: this URL should come from the RoutingService
|
||||
resp.setContent(copiedBuffer("", UTF_8))
|
||||
resp.setHeader("Content-Length", "0")
|
||||
resp.setHeader("Location", "/a/auth")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.lookout.borderpatrol.auth
|
||||
|
||||
import com.twitter.finagle._
|
||||
import com.twitter.util.Future
|
||||
import org.jboss.netty.handler.codec.http.{HttpResponseStatus, DefaultHttpResponse, HttpRequest, HttpResponse}
|
||||
|
||||
/**
|
||||
* Invokes the Authentication service to turn a master session token into a token for a specific service.
|
||||
*
|
||||
* Created by akuhnhausen on 6/11/14.
|
||||
*/
|
||||
class AuthService extends Service[HttpRequest, HttpResponse] {
|
||||
def apply(request: HttpRequest) = {
|
||||
val response = new DefaultHttpResponse(request.getProtocolVersion, HttpResponseStatus.OK)
|
||||
Future.value(response)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package com.lookout.borderpatrol.auth
|
||||
|
||||
import com.lookout.borderpatrol.sessions.SessionStore
|
||||
import com.twitter.finagle.{Service, SimpleFilter}
|
||||
import org.jboss.netty.handler.codec.http.{HttpResponseStatus, HttpMethod, HttpRequest, HttpResponse}
|
||||
|
||||
/**
|
||||
* Created by svij on 6/12/14.
|
||||
*/
|
||||
class TokenFilter(sessionStore: SessionStore) extends SimpleFilter[HttpRequest, HttpResponse]{
|
||||
def apply(request: HttpRequest, service: Service[HttpRequest, HttpResponse]) = {
|
||||
System.out.println("Inside token filter. Uri="+ request.getUri())
|
||||
//TODO: append the service token if exists
|
||||
//get the master token
|
||||
val sessionId = request.getHeader("BORDER_PATROL_SESSION_ID")
|
||||
val session = sessionStore.session(sessionId)
|
||||
session.masterToken map {
|
||||
request.addHeader("master_token", _)
|
||||
}
|
||||
var f_response = service(request)
|
||||
if (request.getUri().contains("auth") && request.getMethod() == HttpMethod.POST) {
|
||||
System.out.println("Inside token filter: extracting master token")
|
||||
// reassign the response future as we are running this function onSuccess
|
||||
f_response = f_response onSuccess { resp: HttpResponse =>
|
||||
if (resp.getStatus() == HttpResponseStatus.OK) {
|
||||
//take the master token and store
|
||||
val master_token = resp.getHeader("master_token")
|
||||
System.out.println("Inside token filter: extracted the master token="+master_token + "; session-id="+sessionId)
|
||||
session.masterToken = master_token
|
||||
resp.removeHeader("master_token")
|
||||
resp.setStatus(HttpResponseStatus.MOVED_PERMANENTLY)
|
||||
resp.setHeader("Content-Length", "0")
|
||||
resp.setHeader("Location", "/b/home")
|
||||
}
|
||||
}
|
||||
}
|
||||
f_response
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package com.lookout.borderpatrol
|
||||
|
||||
/**
|
||||
* Created by akuhnhausen on 6/11/14.
|
||||
*/
|
||||
package object auth {
|
||||
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
package com.lookout
|
||||
|
||||
package object borderpatrol {
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package com.lookout.borderpatrol.routing
|
||||
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
import com.twitter.finagle.http.Request
|
||||
import com.twitter.finagle.http.Response
|
||||
import com.twitter.finagle.Service
|
||||
import com.twitter.finagle.SimpleFilter
|
||||
import com.twitter.finagle.Service
|
||||
import com.twitter.finagle.http.{Request, Response}
|
||||
import com.twitter.finagle.SimpleFilter
|
||||
import scala.collection.immutable.HashMap
|
||||
import org.jboss.netty.handler.codec.http._
|
||||
import scala.util.matching.Regex
|
||||
|
||||
class RoutingFilter
|
||||
extends SimpleFilter[HttpRequest, HttpResponse] {
|
||||
|
||||
// Ideally the route would map a string to a new object with
|
||||
// details like service name and host information etc. For demo purposes we are going for
|
||||
// a string to string mapping of service names. "b" => "smb", "c" => "flexd" but we are hardcoding it
|
||||
// to SERVICE_NAME for simplicity
|
||||
//
|
||||
val routes = HashMap[String, HashMap[String, String]](
|
||||
"/b"->HashMap[String,String]("service_name"->"smb","host"->"localhost","port"->"9292"),
|
||||
"/a"->HashMap[String,String]("service_name"->"checkpoint","host"->"localhost","port"->"4567"),
|
||||
"default"->HashMap[String,String]("service_name"->"flexd","host"->"localhost","port"->"8080"))
|
||||
|
||||
val pattern = new Regex("^/([^/]+)")
|
||||
|
||||
def apply(request: HttpRequest, service: Service[HttpRequest, HttpResponse]) = {
|
||||
// Ideally we would have a RoutingService looking up possible routes and not
|
||||
// have a static lookup table.
|
||||
val req = injectHeaderAndModifyUri(request)
|
||||
service(req)
|
||||
}
|
||||
|
||||
|
||||
def extractServiceFromUri(uri: String): Serializable = {
|
||||
val result = pattern.findFirstIn(uri).getOrElse("default")
|
||||
val serviceUri = {
|
||||
routes.getOrElse(result , "")
|
||||
}
|
||||
serviceUri
|
||||
}
|
||||
|
||||
def injectHeaderAndModifyUri(request: HttpRequest): HttpRequest = {
|
||||
println("INITIAL HEADERS : "+ request.getHeaders)
|
||||
val service = extractServiceFromUri(request.getUri).asInstanceOf[HashMap[String,String]]
|
||||
request.addHeader("SERVICE_NAME", service.get("service_name").getOrElse("SERVICE_NAME"))
|
||||
request.addHeader("ORIGINAL_HOST", request.getHeader("HOST"))
|
||||
request.setHeader("HOST", service.get("host").getOrElse("localhost")+":"+service.get("port").getOrElse("8080"))
|
||||
request.setUri(request.getUri)
|
||||
println("HEADERS AFTER REROUTE : "+ request.getHeaders)
|
||||
request
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package com.lookout.borderpatrol.routing
|
||||
|
||||
/**
|
||||
* Created by akuhnhausen on 6/11/14.
|
||||
*/
|
||||
class RoutingService {
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package com.lookout.borderpatrol
|
||||
|
||||
/**
|
||||
* Created by akuhnhausen on 6/11/14.
|
||||
*/
|
||||
package object routing {
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package com.lookout.borderpatrol.sessions
|
||||
|
||||
import com.twitter.finagle.SimpleFilter
|
||||
import com.twitter.finagle.Service
|
||||
import org.jboss.netty.handler.codec.http._
|
||||
import java.util.UUID.randomUUID
|
||||
import org.jboss.netty.handler.codec.http.DefaultCookie
|
||||
import scala.collection.JavaConversions._
|
||||
import com.twitter.logging.Logging
|
||||
import com.twitter.util.Try
|
||||
|
||||
class SessionIDFilter(sessionStore: SessionStore) extends SimpleFilter[HttpRequest, HttpResponse] {
|
||||
|
||||
val cookieKey = "border_session"
|
||||
val maxAge = 24 * 60 * 60
|
||||
|
||||
def apply(request: HttpRequest, service: Service[HttpRequest, HttpResponse]) = {
|
||||
val id = getIDFromRequest(request) getOrElse generateNewID
|
||||
request.setHeader("BORDER_PATROL_SESSION_ID", id)
|
||||
System.out.println("Session ID: %s".format(id))
|
||||
|
||||
service(request) onSuccess (setCookie(_, id))
|
||||
}
|
||||
|
||||
def generateNewID: String = {
|
||||
val id = randomUUID.toString
|
||||
sessionStore.addSession(id)
|
||||
id
|
||||
}
|
||||
|
||||
def getIDFromRequest(request: HttpRequest): Option[String] = {
|
||||
Option(request.getHeader(HttpHeaders.Names.COOKIE)) flatMap {
|
||||
getIDFromValidCookie(_)
|
||||
}
|
||||
}
|
||||
|
||||
def getIDFromValidCookie(cookieHeader: String): Option[String] = {
|
||||
val cookies = new CookieDecoder().decode(cookieHeader).toSet
|
||||
val cookie: Option[Cookie] = cookies find {
|
||||
validCookie(_)
|
||||
}
|
||||
cookie map {
|
||||
_.getValue
|
||||
}
|
||||
}
|
||||
|
||||
def validCookie(cookie: Cookie): Boolean = {
|
||||
cookie.getName == cookieKey
|
||||
}
|
||||
|
||||
def setCookie(response: HttpResponse, sessionId: String): Unit = {
|
||||
val cookie = new DefaultCookie(cookieKey, sessionId)
|
||||
cookie.setMaxAge(maxAge)
|
||||
cookie.setDomain("lookout.com")
|
||||
cookie.setSecure(true)
|
||||
response.setHeader(HttpHeaders.Names.SET_COOKIE, cookie)
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package com.lookout.borderpatrol.sessions
|
||||
|
||||
import scala.collection.mutable.Map
|
||||
|
||||
class SessionStore {
|
||||
/*
|
||||
{
|
||||
<session_id>: {
|
||||
<master_token>: String,
|
||||
<destination>: String,
|
||||
<service1>: String, ...
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
private var store = Map[String, Map[String, String]]()
|
||||
|
||||
def session(id: String) = new Session(id)
|
||||
|
||||
def addSession(id: String) = store += (id -> Map[String,String]())
|
||||
|
||||
class Session(id: String) {
|
||||
|
||||
var sessionStore = store get id
|
||||
|
||||
def masterToken_= (token: String): Unit = sessionStore.get += ("master_token" -> token)
|
||||
|
||||
def masterToken = store get id flatMap { _ get "master_token" }
|
||||
|
||||
def serviceToken_= (t: (String, String)) = sessionStore.get += (t._1 -> t._2)
|
||||
|
||||
def serviceToken = store get id
|
||||
|
||||
def destination_= (destination: String) = sessionStore.get += ("destination" -> destination)
|
||||
|
||||
def destination = store get id flatMap { _ get "destination" }
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package com.lookout.borderpatrol.sessions
|
||||
|
||||
import com.twitter.finagle.Service
|
||||
import com.twitter.finagle.SimpleFilter
|
||||
import com.twitter.finagle.Service
|
||||
import com.twitter.finagle.SimpleFilter
|
||||
import org.jboss.netty.handler.codec.http._
|
||||
import scala.collection.immutable.{Map, HashMap}
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.fasterxml.jackson.module.scala.DefaultScalaModule
|
||||
|
||||
class SessionStoreFilter(sessionStore: SessionStore) extends SimpleFilter[HttpRequest, HttpResponse] {
|
||||
def apply(request: HttpRequest, service: Service[HttpRequest, HttpResponse]) = {
|
||||
val serviceName = request.getHeader("SERVICE_NAME")
|
||||
val sessionId = request.getHeader("BORDER_PATROL_SESSION_ID")
|
||||
val session = sessionStore.session(sessionId)
|
||||
session.serviceToken map { _ get serviceName } map {
|
||||
request.setHeader("Auth-Token", _)
|
||||
}
|
||||
|
||||
System.out.println("Auth-Token: %s".format(request.getHeader("Auth-Token")))
|
||||
service(request)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package com.lookout.borderpatrol
|
||||
|
||||
/**
|
||||
* Created by akuhnhausen on 6/11/14.
|
||||
*/
|
||||
package object sessions {
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package com
|
||||
|
||||
/**
|
||||
*
|
||||
* Start with [[com.lookout.borderpatrol]].
|
||||
*
|
||||
*/
|
||||
package object lookout
|
|
@ -0,0 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Start with [[com.lookout.borderpatrol]].
|
||||
*
|
||||
*/
|
||||
package object com
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
import com.lookout.borderpatrol._
|
||||
/*
|
||||
class BorderPatrolAppSpec extends UnitSpec {
|
||||
|
||||
"A Server" should "do something fun" in {
|
||||
true should be (true)
|
||||
}
|
||||
|
||||
it should "throw a Runtime exception when it wants" in {
|
||||
a [RuntimeException] should be thrownBy {
|
||||
throw new RuntimeException("testing!")
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
|
@ -0,0 +1,13 @@
|
|||
require 'sinatra'
|
||||
require 'json'
|
||||
|
||||
set :bind, '0.0.0.0'
|
||||
|
||||
get '/auth' do
|
||||
"this is a login page"
|
||||
end
|
||||
|
||||
post '/auth' do
|
||||
headers "master_token" => "super_secret"
|
||||
"login success!"
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.lookout</groupId>
|
||||
<artifactId>borderpatrol</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>0.0.1</version>
|
||||
<modules>
|
||||
<module>borderpatrol-core</module>
|
||||
</modules>
|
||||
</project>
|
|
@ -0,0 +1,32 @@
|
|||
import sbt._
|
||||
import Keys._
|
||||
|
||||
object BorderPatrol extends Build {
|
||||
val libVersion = "0.0.1"
|
||||
|
||||
val sharedSettings = Seq(
|
||||
version := libVersion,
|
||||
organization := "com.lookout",
|
||||
scalaVersion := "2.10.3",
|
||||
libraryDependencies ++= Seq(
|
||||
"com.twitter" %% "twitter-server" % "1.0.2",
|
||||
"org.scalatest" % "scalatest_2.11" % "2.2.0" % "test"
|
||||
),
|
||||
|
||||
scalacOptions ++= Seq("-encoding", "utf8"),
|
||||
scalacOptions += "-deprecation",
|
||||
javacOptions ++= Seq("-source", "1.6", "-target", "1.6"),
|
||||
javacOptions in doc := Seq("-source", "1.6"),
|
||||
|
||||
resolvers += "twitter-repo" at "http://maven.twttr.com"
|
||||
)
|
||||
|
||||
|
||||
lazy val borderPatrolCore = Project(
|
||||
id = "borderpatrol-core",
|
||||
base = file("borderpatrol-core"),
|
||||
settings = Project.defaultSettings ++ sharedSettings
|
||||
).settings(
|
||||
name := "borderpatrol-core"
|
||||
)
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
sbt.version=0.13.5
|
|
@ -0,0 +1,40 @@
|
|||
#!/bin/bash
|
||||
|
||||
sbtver=0.13.5
|
||||
sbtjar=sbt-launch.jar
|
||||
sbtsha128=f6308bd94bebdd37eb5e2fda732694ce0f34be74
|
||||
|
||||
sbtrepo=http://repo.typesafe.com/typesafe/ivy-releases/org.scala-sbt/sbt-launch
|
||||
|
||||
if [ ! -f $sbtjar ]; then
|
||||
echo "downloading $sbtjar" 1>&2
|
||||
if ! curl --silent --fail --remote-name $sbtrepo/$sbtver/$sbtjar; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
checksum=`openssl dgst -sha1 $sbtjar | awk '{ print $2 }'`
|
||||
if [ "$checksum" != $sbtsha128 ]; then
|
||||
echo "bad $sbtjar. delete $sbtjar and run $0 again."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
[ -f ~/.sbtconfig ] && . ~/.sbtconfig
|
||||
|
||||
java -ea \
|
||||
$SBT_OPTS \
|
||||
$JAVA_OPTS \
|
||||
-Djava.net.preferIPv4Stack=true \
|
||||
-XX:+AggressiveOpts \
|
||||
-XX:+UseParNewGC \
|
||||
-XX:+UseConcMarkSweepGC \
|
||||
-XX:+CMSParallelRemarkEnabled \
|
||||
-XX:+CMSClassUnloadingEnabled \
|
||||
-XX:MaxPermSize=1024m \
|
||||
-XX:SurvivorRatio=128 \
|
||||
-XX:MaxTenuringThreshold=0 \
|
||||
-Xss8M \
|
||||
-Xms512M \
|
||||
-Xmx1G \
|
||||
-server \
|
||||
-jar $sbtjar "$@"
|
|
@ -0,0 +1,19 @@
|
|||
require 'rubygems'
|
||||
require 'rack'
|
||||
|
||||
Rack::Server.start :app => Proc.new {|env|
|
||||
# pick http headers
|
||||
http_headers = env.select { |key, value| !!(key.to_s =~ /(HTTP).+/i) }
|
||||
response_code = 200
|
||||
response_code = 401 if http_headers['HTTP_MASTER_TOKEN'].nil?
|
||||
req_body = env['rack.input']
|
||||
resp_body = "Headers: "
|
||||
http_headers.each { |k,v|
|
||||
resp_body << k.gsub("HTTP_", "")
|
||||
resp_body << ":#{v}"
|
||||
resp_body << ","
|
||||
}
|
||||
resp_body << "\nRequest Body= #{req_body}"
|
||||
p "request received = #{resp_body}"
|
||||
[response_code, {"Content-Type" => "text/html"}, [resp_body]]
|
||||
}, :Port => 9292
|
Loading…
Reference in New Issue