You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by jv...@apache.org on 2017/03/11 18:09:51 UTC

[1/5] incubator-trafficcontrol git commit: cosmetics

Repository: incubator-trafficcontrol
Updated Branches:
  refs/heads/master cb08fc3eb -> 4d8182f4e


cosmetics


Project: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/commit/844f7657
Tree: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/tree/844f7657
Diff: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/diff/844f7657

Branch: refs/heads/master
Commit: 844f765706c39d343b55f0fefb87bc6993df5d19
Parents: 3125217
Author: Amir Yeshurun <am...@qwilt.com>
Authored: Tue Feb 28 01:14:35 2017 +0200
Committer: Jan van Doorn <ja...@cable.comcast.com>
Committed: Sat Mar 11 11:06:09 2017 -0700

----------------------------------------------------------------------
 traffic_ops/experimental/webfront/webfront.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/844f7657/traffic_ops/experimental/webfront/webfront.go
----------------------------------------------------------------------
diff --git a/traffic_ops/experimental/webfront/webfront.go b/traffic_ops/experimental/webfront/webfront.go
index 7b14b47..60371a4 100644
--- a/traffic_ops/experimental/webfront/webfront.go
+++ b/traffic_ops/experimental/webfront/webfront.go
@@ -13,7 +13,7 @@
     limitations under the License.
 */
 
-//  Started with https://github.com/nf/webfront/blob/master/main.go
+// Started with https://github.com/nf/webfront/blob/master/main.go
 // by Andrew Gerrand <ad...@golang.org>
 
 package main


[2/5] incubator-trafficcontrol git commit: add apache license headers

Posted by jv...@apache.org.
add apache license headers


Project: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/commit/31252171
Tree: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/tree/31252171
Diff: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/diff/31252171

Branch: refs/heads/master
Commit: 312521716e1a1fede20ffbf0133a871d8b194ccb
Parents: 610f69c
Author: Amir Yeshurun <am...@qwilt.com>
Authored: Mon Feb 27 23:51:12 2017 +0200
Committer: Jan van Doorn <ja...@cable.comcast.com>
Committed: Sat Mar 11 11:06:09 2017 -0700

----------------------------------------------------------------------
 traffic_ops/experimental/auth/Dockerfile             | 14 ++++++++++++++
 traffic_ops/experimental/auth/auth.go                | 15 +++++++++++++++
 traffic_ops/experimental/webfront/Dockerfile         | 14 ++++++++++++++
 .../webfront/simpleserver/simpleserver.go            | 15 +++++++++++++++
 traffic_ops/experimental/webfront/startfakes.sh      | 14 ++++++++++++++
 traffic_ops/experimental/webfront/webfront.go        | 15 +++++++++++++++
 6 files changed, 87 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/31252171/traffic_ops/experimental/auth/Dockerfile
----------------------------------------------------------------------
diff --git a/traffic_ops/experimental/auth/Dockerfile b/traffic_ops/experimental/auth/Dockerfile
index 4ec7a98..ff39144 100644
--- a/traffic_ops/experimental/auth/Dockerfile
+++ b/traffic_ops/experimental/auth/Dockerfile
@@ -1,3 +1,17 @@
+#
+#    Licensed 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.
+#
+
 # Start from a Debian image with the latest version of Go installed
 # and a workspace (GOPATH) configured at /go.
 FROM golang

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/31252171/traffic_ops/experimental/auth/auth.go
----------------------------------------------------------------------
diff --git a/traffic_ops/experimental/auth/auth.go b/traffic_ops/experimental/auth/auth.go
index 0cedfef..8ffbc5c 100644
--- a/traffic_ops/experimental/auth/auth.go
+++ b/traffic_ops/experimental/auth/auth.go
@@ -1,3 +1,18 @@
+/*
+
+    Licensed 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 main
 
 import (

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/31252171/traffic_ops/experimental/webfront/Dockerfile
----------------------------------------------------------------------
diff --git a/traffic_ops/experimental/webfront/Dockerfile b/traffic_ops/experimental/webfront/Dockerfile
index c46e36a..cf6e4d3 100644
--- a/traffic_ops/experimental/webfront/Dockerfile
+++ b/traffic_ops/experimental/webfront/Dockerfile
@@ -1,3 +1,17 @@
+#
+#    Licensed 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.
+#
+
 # Start from a Debian image with the latest version of Go installed
 # and a workspace (GOPATH) configured at /go.
 FROM golang

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/31252171/traffic_ops/experimental/webfront/simpleserver/simpleserver.go
----------------------------------------------------------------------
diff --git a/traffic_ops/experimental/webfront/simpleserver/simpleserver.go b/traffic_ops/experimental/webfront/simpleserver/simpleserver.go
index e4baeb2..1743424 100644
--- a/traffic_ops/experimental/webfront/simpleserver/simpleserver.go
+++ b/traffic_ops/experimental/webfront/simpleserver/simpleserver.go
@@ -1,3 +1,18 @@
+/*
+
+    Licensed 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 main
 
 import (

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/31252171/traffic_ops/experimental/webfront/startfakes.sh
----------------------------------------------------------------------
diff --git a/traffic_ops/experimental/webfront/startfakes.sh b/traffic_ops/experimental/webfront/startfakes.sh
index 66675e5..ba263ca 100644
--- a/traffic_ops/experimental/webfront/startfakes.sh
+++ b/traffic_ops/experimental/webfront/startfakes.sh
@@ -1,3 +1,17 @@
+#
+#    Licensed 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.
+#
+
 go run simpleserver/simpleserver.go  8001 &
 go run simpleserver/simpleserver.go  8002 &
 go run simpleserver/simpleserver.go  8003 &

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/31252171/traffic_ops/experimental/webfront/webfront.go
----------------------------------------------------------------------
diff --git a/traffic_ops/experimental/webfront/webfront.go b/traffic_ops/experimental/webfront/webfront.go
index 247ea24..7b14b47 100644
--- a/traffic_ops/experimental/webfront/webfront.go
+++ b/traffic_ops/experimental/webfront/webfront.go
@@ -1,3 +1,18 @@
+/*
+
+    Licensed 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.
+*/
+
 //  Started with https://github.com/nf/webfront/blob/master/main.go
 // by Andrew Gerrand <ad...@golang.org>
 


[3/5] incubator-trafficcontrol git commit: original webfront, auth services taken form https://github.com/rarenivar/project5799

Posted by jv...@apache.org.
original webfront, auth services taken form https://github.com/rarenivar/project5799


Project: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/commit/c6221c2e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/tree/c6221c2e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/diff/c6221c2e

Branch: refs/heads/master
Commit: c6221c2eaa10b287ce8c55aec0b5269829971b3e
Parents: cb08fc3
Author: Amir Yeshurun <am...@qwilt.com>
Authored: Sun Feb 26 22:51:53 2017 +0200
Committer: Jan van Doorn <ja...@cable.comcast.com>
Committed: Sat Mar 11 11:06:09 2017 -0700

----------------------------------------------------------------------
 traffic_ops/experimental/auth/Dockerfile        |  23 ++
 traffic_ops/experimental/auth/auth.config       |   8 +
 traffic_ops/experimental/auth/auth.go           | 172 +++++++++++
 traffic_ops/experimental/auth/server.key        |  27 ++
 traffic_ops/experimental/auth/server.pem        |  21 ++
 traffic_ops/experimental/webfront/Dockerfile    |  25 ++
 traffic_ops/experimental/webfront/README.md     |  98 +++++++
 traffic_ops/experimental/webfront/rules.json    |  32 ++
 traffic_ops/experimental/webfront/server.key    |  27 ++
 traffic_ops/experimental/webfront/server.pem    |  21 ++
 .../webfront/simpleserver/server.key            |  27 ++
 .../webfront/simpleserver/server.pem            |  21 ++
 .../webfront/simpleserver/simpleserver.go       |  25 ++
 traffic_ops/experimental/webfront/startfakes.sh |   7 +
 .../experimental/webfront/webfront.config       |   5 +
 traffic_ops/experimental/webfront/webfront.go   | 293 +++++++++++++++++++
 16 files changed, 832 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/c6221c2e/traffic_ops/experimental/auth/Dockerfile
----------------------------------------------------------------------
diff --git a/traffic_ops/experimental/auth/Dockerfile b/traffic_ops/experimental/auth/Dockerfile
new file mode 100644
index 0000000..4ec7a98
--- /dev/null
+++ b/traffic_ops/experimental/auth/Dockerfile
@@ -0,0 +1,23 @@
+# Start from a Debian image with the latest version of Go installed
+# and a workspace (GOPATH) configured at /go.
+FROM golang
+
+# Copy the local package files to the container's workspace.
+# Note: need to move to ~/go?
+ADD . /go/src/github.com/rarenivar/project5799/auth
+
+# Build the outyet command inside the container.
+# (You may fetch or manage dependencies here,
+# either manually or with a tool like "godep".)
+RUN go get github.com/dgrijalva/jwt-go
+RUN go get github.com/jmoiron/sqlx
+RUN go get github.com/lib/pq
+WORKDIR ./src/github.com/rarenivar/project5799/auth
+RUN export GOBIN=$GOPATH/bin && go install auth.go
+
+# Document that the service listens on port 9000.
+EXPOSE 8080
+
+# Run the outyet command by default when the container starts.
+ENTRYPOINT /go/bin/auth auth.config
+

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/c6221c2e/traffic_ops/experimental/auth/auth.config
----------------------------------------------------------------------
diff --git a/traffic_ops/experimental/auth/auth.config b/traffic_ops/experimental/auth/auth.config
new file mode 100644
index 0000000..642923e
--- /dev/null
+++ b/traffic_ops/experimental/auth/auth.config
@@ -0,0 +1,8 @@
+{
+	"dbName":"amiry",
+	"dbUser":"amiry",
+	"dbPassword":"blabla",
+	"dbServer":"localhost",
+	"dbPort":5432,
+	"listenerPort":"8080"
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/c6221c2e/traffic_ops/experimental/auth/auth.go
----------------------------------------------------------------------
diff --git a/traffic_ops/experimental/auth/auth.go b/traffic_ops/experimental/auth/auth.go
new file mode 100644
index 0000000..937124f
--- /dev/null
+++ b/traffic_ops/experimental/auth/auth.go
@@ -0,0 +1,172 @@
+package main
+
+import (
+	"encoding/json"
+	"fmt"
+	jwt "github.com/dgrijalva/jwt-go"
+	"github.com/jmoiron/sqlx"
+	_ "github.com/lib/pq"
+	"io/ioutil"
+	"log"
+	"net/http"
+	"os"
+	"path"
+	"time"
+)
+
+// Config holds the configuration of the server.
+type Config struct {
+	DbName       string `json:"dbName"`
+	DbUser       string `json:"dbUser"`
+	DbPassword   string `json:"dbPassword"`
+	DbServer     string `json:"dbServer,omitempty"`
+	DbPort       uint   `json:"dbPort,omitempty"`
+	ListenerPort string `json:"listenerPort"`
+}
+
+type User struct {
+	Username  string `db:"username" json:"username"`
+	FirstName string `db:"first_name" json:"firstName,omitempty"`
+	LastName  string `db:"last_name" json:"lastName,omitempty"`
+	Password  string `db:"password" json:"password"`
+}
+
+type Claims struct {
+    Capabilities []string `json:"cap"`
+    jwt.StandardClaims
+}
+
+type TokenResponse struct {
+	Token string
+}
+
+var db *sqlx.DB // global and simple
+
+func printUsage() {
+	exampleConfig := `{
+	"dbName":"my-db",
+	"dbUser":"my-user",
+	"dbPassword":"secret",
+	"dbServer":"localhost",
+	"dbPort":5432,
+	"listenerPort":"8080"
+}`
+	Logger.Println("Usage: " + path.Base(os.Args[0]) + " configfile")
+	Logger.Println("")
+	Logger.Println("Example config file:")
+	Logger.Println(exampleConfig)
+}
+
+var Logger *log.Logger
+
+func main() {
+	if len(os.Args) < 2 {
+		printUsage()
+		return
+	}
+
+	// log.SetOutput(os.Stdout)
+	Logger = log.New(os.Stdout, " ", log.Ldate|log.Ltime|log.Lshortfile)
+
+	file, err := os.Open(os.Args[1])
+	if err != nil {
+		Logger.Println("Error opening config file:", err)
+		return
+	}
+	decoder := json.NewDecoder(file)
+	config := Config{}
+	err = decoder.Decode(&config)
+	if err != nil {
+		Logger.Println("Error reading config file:", err)
+		return
+	}
+
+	db, err = InitializeDatabase(config.DbUser, config.DbPassword, config.DbName, config.DbServer, config.DbPort)
+	if err != nil {
+		Logger.Println("Error initializing database:", err)
+		return
+	}
+
+	http.HandleFunc("/", handler)
+	if _, err := os.Stat("server.pem"); os.IsNotExist(err) {
+		Logger.Fatal("server.pem file not found")
+	}
+	if _, err := os.Stat("server.key"); os.IsNotExist(err) {
+		Logger.Fatal("server.key file not found")
+	}
+	Logger.Printf("Starting server on port " + config.ListenerPort + "...")
+	Logger.Fatal(http.ListenAndServeTLS(":"+config.ListenerPort, "server.pem", "server.key", nil))
+}
+
+func InitializeDatabase(username, password, dbname, server string, port uint) (*sqlx.DB, error) {
+	connString := fmt.Sprintf("host=%s dbname=%s user=%s password=%s sslmode=disable", server, dbname, username, password)
+
+	db, err := sqlx.Connect("postgres", connString)
+	if err != nil {
+		return nil, err
+	}
+
+	return db, nil
+}
+
+func handler(w http.ResponseWriter, r *http.Request) {
+
+	Logger.Println(r.Method, r.URL.Scheme, r.Host, r.URL.RequestURI())
+
+	if r.Method == "POST" {
+		var u User
+		userlist := []User{}
+		body, err := ioutil.ReadAll(r.Body)
+		log.Println(string(body))
+		if err != nil {
+			Logger.Println("Error reading body: ", err.Error())
+			http.Error(w, "Error reading body: "+err.Error(), http.StatusBadRequest)
+			return
+		}
+		err = json.Unmarshal(body, &u)
+		if err != nil {
+			Logger.Println("Error unmarshalling JSON: ", err.Error())
+			http.Error(w, "Invalid JSON: "+err.Error(), http.StatusBadRequest)
+			return
+		}
+		stmt, err := db.PrepareNamed("SELECT * FROM users WHERE username=:username")
+		err = stmt.Select(&userlist, u)
+		if err != nil {
+			Logger.Println(err.Error())
+			http.Error(w, "Database error: "+err.Error(), http.StatusInternalServerError)
+			return
+		}
+		if len(userlist) == 0 || userlist[0].Password != u.Password {
+			http.Error(w, "Invalid username/password ", http.StatusUnauthorized)
+			return
+		}
+
+		claims := Claims {
+	        []string{"read-a", "write-a", "read-b"}, // TODO(amiry) - Read from DB
+	        jwt.StandardClaims {
+	        	Subject: u.Username,
+	            ExpiresAt: time.Now().Add(time.Hour * 24).Unix(), // TODO(amiry) - Use shorter expiration
+	        },
+	    }
+
+		token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
+
+		tokenString, err := token.SignedString([]byte("CAmeRAFiveSevenNineNine")) // TODO(amiry) - Where to keep secret?
+		if err != nil {
+			Logger.Println(err.Error())
+			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return
+		}
+		js, err := json.Marshal(TokenResponse{Token: tokenString})
+		if err != nil {
+			Logger.Println(err.Error())
+			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return
+		}
+		// w.WriteHeader(http.StatusOK)
+		w.Header().Set("Content-Type", "application/json")
+		w.Write(js)
+		return
+	}
+	http.Error(w, r.Method+" "+r.URL.Path+" not valid for this microservice", http.StatusNotFound)
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/c6221c2e/traffic_ops/experimental/auth/server.key
----------------------------------------------------------------------
diff --git a/traffic_ops/experimental/auth/server.key b/traffic_ops/experimental/auth/server.key
new file mode 100644
index 0000000..b674147
--- /dev/null
+++ b/traffic_ops/experimental/auth/server.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEA0g8TSrCJLfzMxzCB+zLo19NIrOAA2kR25vi8Hu+aM2PGxJbH
+FPSV0LG1HF3l/4QoG1JNYKuyXaPFDtPcefU7fQ7MqpAiBWj2HyIfnKyZyUX867Pg
+2CnSPTgMZyK3NMSnkAG+FSZzXKj6Vxjh0mKN1X+JRqyv1c/rWLg3RxecuVdq0D23
+l/1nZPWidiRp2XhUKeO3L3rLKu9tf80HJZ1TN3TsUxOGUgZHectN577qAaHr3KzD
+HVA4v7fmNRXQEUg4Iax8FxWIw0CQOFY9+lUqW1TKr7UmrqnzmhQmLFNBP5wuU1fI
+yz5HqNeR2VOt10VDBfYg7Wy08mFsSr3bhj9GMwIDAQABAoIBAQCC+H9QzG1bzQlp
+EKealg1zs/rWPvyJGrMAJAo3R7FfZVCjdlc+i5l1e7euriUfgaj4EALKyYL2u4u8
+SQBo0ix7NuUJW8C6ms0KcF5Bc6SXSBoAZDFG1hyNqwqgq5aLQiovscZwrX60QW+F
+KrByWpyQh2pyNG2V5IOa15EvtFs1e1f7+DCZ/KLjd5odxEZ93lLcDMQ4zmSl47uR
+I5rdixCQm8slUtRJxAB+nRck5htVGY8cwT6c+hx/GlZqY6xynMOwa9pC3zFegnr3
+nvHIiFEVu0CksaVBZNRe0S92r8VjHQPVRBa87Tsom6vJ0GxaeDfXchedrklCxMJh
+Y+QOPIVhAoGBAPgDxXGBD7VaUsBgimJKE1Q/inT2aZtwKrJi4l2fRE1Q0kOZvePv
+/LMiUZwcV0M+y45Y0VU2VXIdqAC1tYFhFfRKdmjCABFSidyhpIMJJZQrX3fFEDZq
+Vt95PrjlRC3+AVvVXVNWOxP4ObgorPzqXKtgxt10OltJfiLHHe0LF9nJAoGBANjS
+dUNU9OhCFA54MpfKtNLXvnYsxXigkN9rXAiOt9yd3x4l3o1EJs9t4a6stgzPaXDc
+ANkIPf1xsO9N0c+rikYQRo+JmbTaAQhac19NF7guTV6lHRa9bR4N4O14+62oXFEX
+3z5hp2Tr0/1qjp62ubDR8S7zY8ACsKiqd0msZ94bAoGAEy3XeuuMF24gsBfHG8q2
+q/Et99WGXSrTYnAbKTpDwebaG7gr4xCP7hpdTUEzzlNw0lUz+u70tJpuf3+Nxa+I
+TxfjCD7YWn6TgqhNXIS8jzS7cTugAVU/2pA5tXqlRxk5aayaRvOIJgcwD3m1xuko
+uWgGeOGgEachRfc37TjKY2ECgYAmDMDxYP5dqAL3Cxbt1m/nNF9DQ9YftiXWX3PW
+OJ2BhN773m9w4Q3ihwj862hDVT7OxH0NmUmvqX0AceqpBBSO+Ro45E/qEfvuaFko
+11GbS9zeCCHTtMhqZssbQYkBT7Nrs8HEo8SJjG02YrXGmpB5vE4UDDhsIMy5vLiU
+YEIWEwKBgQCXvBaNGJxPDu3//8yJJC4gFSWUxWYZ9x12Kke6AaUoeEn8RjTlaLRm
+Ol1ZiqHTSbRJQHjqmwKJAWSA3QX4S3ISeVOms7k30Bt02m4W0NgVRB2GxkFcnESH
+OxREDAQXG2lLP9O2HZPPHZ9aKKFM+M0GlOdQlqKk3AHPx33qCXLYtg==
+-----END RSA PRIVATE KEY-----

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/c6221c2e/traffic_ops/experimental/auth/server.pem
----------------------------------------------------------------------
diff --git a/traffic_ops/experimental/auth/server.pem b/traffic_ops/experimental/auth/server.pem
new file mode 100644
index 0000000..c09c2ca
--- /dev/null
+++ b/traffic_ops/experimental/auth/server.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDbzCCAlegAwIBAgIJAJozT3F7lmQwMA0GCSqGSIb3DQEBCwUAME4xCzAJBgNV
+BAYTAlVTMQswCQYDVQQIDAJDTzEPMA0GA1UEBwwGRGVudmVyMSEwHwYDVQQKDBhJ
+bnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYwMzI2MjIyODExWhcNMjYwMzI0
+MjIyODExWjBOMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ08xDzANBgNVBAcMBkRl
+bnZlcjEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkq
+hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0g8TSrCJLfzMxzCB+zLo19NIrOAA2kR2
+5vi8Hu+aM2PGxJbHFPSV0LG1HF3l/4QoG1JNYKuyXaPFDtPcefU7fQ7MqpAiBWj2
+HyIfnKyZyUX867Pg2CnSPTgMZyK3NMSnkAG+FSZzXKj6Vxjh0mKN1X+JRqyv1c/r
+WLg3RxecuVdq0D23l/1nZPWidiRp2XhUKeO3L3rLKu9tf80HJZ1TN3TsUxOGUgZH
+ectN577qAaHr3KzDHVA4v7fmNRXQEUg4Iax8FxWIw0CQOFY9+lUqW1TKr7Umrqnz
+mhQmLFNBP5wuU1fIyz5HqNeR2VOt10VDBfYg7Wy08mFsSr3bhj9GMwIDAQABo1Aw
+TjAdBgNVHQ4EFgQUdme3OnuvS+09/3Nkx1FS/4xgXoUwHwYDVR0jBBgwFoAUdme3
+OnuvS+09/3Nkx1FS/4xgXoUwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC
+AQEANNo5qASaoCc5/Utr10KIO/KoFesWL0v0bDIG3r0HaEp2gD44o884yQ8pFDNR
+bhUjs1SaHHcnGX5X3OGJVuP2vuz0pFaeKZJUawT1DTwaXQCTkRFw0Cb7oWdF6/FV
+pXuLBXWvEsu19jnrZGQbJw1lsOchPDNpp/h460JBWQOOYRfu3jSyBMwih40lEb+F
+1lA943aA2oGsDYJHnGRpUMLafe4gqcGWpfHUf2TaGe+tUSI7+JrhYLzjRyqTBdD3
+5Ss+eQo5tP0aOVMMCMCHmFfxgjBHGu4syQW5VYIZtzWMEKu2fEZCjkbV6XwVYVFL
+SKh7EgT1te7yUhfLSAF2969WHg==
+-----END CERTIFICATE-----

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/c6221c2e/traffic_ops/experimental/webfront/Dockerfile
----------------------------------------------------------------------
diff --git a/traffic_ops/experimental/webfront/Dockerfile b/traffic_ops/experimental/webfront/Dockerfile
new file mode 100644
index 0000000..c46e36a
--- /dev/null
+++ b/traffic_ops/experimental/webfront/Dockerfile
@@ -0,0 +1,25 @@
+# Start from a Debian image with the latest version of Go installed
+# and a workspace (GOPATH) configured at /go.
+FROM golang
+
+# Copy the local package files to the container's workspace.
+# Note: need to move to ~/go?
+ADD . /go/src/github.com/rarenivar/project5799/webfront
+
+# Build the outyet command inside the container.
+# (You may fetch or manage dependencies here,
+# either manually or with a tool like "godep".)
+RUN go get github.com/dgrijalva/jwt-go
+#RUN ls -lR
+WORKDIR ./src/github.com/rarenivar/project5799/webfront
+#RUN cd ./src/github.com/rarenivar/project5799/webfront && export GOBIN=$GOPATH/bin && go install webfront.go
+RUN export GOBIN=$GOPATH/bin && go install webfront.go
+#RUN ls -l
+#RUN go install webfront.go
+
+# Document that the service listens on port 9000.
+EXPOSE 9000
+
+# Run the outyet command by default when the container starts.
+ENTRYPOINT /go/bin/webfront webfront.config
+

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/c6221c2e/traffic_ops/experimental/webfront/README.md
----------------------------------------------------------------------
diff --git a/traffic_ops/experimental/webfront/README.md b/traffic_ops/experimental/webfront/README.md
new file mode 100644
index 0000000..041a219
--- /dev/null
+++ b/traffic_ops/experimental/webfront/README.md
@@ -0,0 +1,98 @@
+This application - webfront is a reverse proxy written in go that can front any number of microservices. It uses a rules file to map from requested host/path to microservice host/port/path.  Example rule file:
+
+   
+    [
+		{"Host": "local.com", "Path" : "/8001", "Forward": "localhost:8001"},
+		{"Host": "local.com", "Path" : "/8002", "Forward": "localhost:8002"},
+		{"Host": "local.com", "Path" : "/8003", "Forward": "localhost:8003"},
+		{"Host": "local.com", "Path" : "/8004", "Forward": "localhost:8004"},
+		{"Host": "local.com", "Path" : "/8005", "Forward": "localhost:8005"},
+		{"Host": "local.com", "Path" : "/8006", "Forward": "localhost:8006"},
+		{"Host": "local.com", "Path" : "/8007", "Forward": "localhost:8007"}
+	]
+
+
+No restart is needed to re-read the rule file and apply; within 60 seconds of a change in the file, it will pick up the new mappings.
+
+To run
+
+	go run webfront.go -rules=rules.json -https=:9000 -https_cert=server.pem -https_key=server.key 
+
+(or compile a binary, and run that)
+
+To get a token:
+
+	curl --insecure -Lkvs --header "Content-Type:application/json" -XPOST https://localhost:9000/login -d'{"username":"jvd", "password":"tootoo"}'
+   
+in my case that returned: 
+
+	{"Token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJQYXNzd29yZCI6InRvb3RvbyIsIlVzZXIiOiIiLCJleHAiOjE0NTg5NDg2MTl9.quCwZ5vghVBucxMxQ4fSfD84yw_yPEp9qLGGQNcHNUk"}``
+   
+ Example:
+  
+	[jvd@laika webfront (master *=)]$ curl --insecure -Lkvs --header "Content-Type:application/json" -XPOST https://localhost:9000/login -d'{"username":"jvd", "password":"tootoo"}'
+	*   Trying ::1...
+	* Connected to localhost (::1) port 9000 (#0)
+	* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+	* Server certificate: CU
+	> POST /login HTTP/1.1
+	> Host: localhost:9000
+	> User-Agent: curl/7.43.0
+	> Accept: */*
+	> Content-Type:application/json
+	> Content-Length: 39
+	>
+	* upload completely sent off: 39 out of 39 bytes
+	< HTTP/1.1 200 OK
+	< Content-Type: application/json
+	< Date: Thu, 24 Mar 2016 23:30:19 GMT
+	< Content-Length: 157
+	<
+	* Connection #0 to host localhost left intact
+	{"Token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJQYXNzd29yZCI6InRvb3RvbyIsIlVzZXIiOiIiLCJleHAiOjE0NTg5NDg2MTl9.quCwZ5vghVBucxMxQ4fSfD84yw_yPEp9qLGGQNcHNUk"}[jvd@laika webfront (master *=)]$
+ 
+ * To use a token: 
+
+	curl --insecure -H'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJQYXNzd29yZCI6InRvb3RvbyIsIlVzZXIiOiIiLCJleHAiOjE0NTg5NDg2MTl9.quCwZ5vghVBucxMxQ4fSfD84yw_yPEp9qLGGQNcHNUk' -Lkvs  https://localhost:9000/8003/r
+
+Example:
+
+   
+    [jvd@laika webfront (master *%=)]$ curl --insecure -H'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJQYXNzd29yZCI6InRvb3RvbyIsIlVzZXIiOiIiLCJleHAiOjE0NTg5NDg2MTl9.quCwZ5vghVBucxMxQ4fSfD84yw_yPEp9qLGGQNcHNUk' -Lkvs  https://localhost:9000/8003/r
+	*   Trying ::1...
+	* Connected to localhost (::1) port 9000 (#0)
+	* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+	* Server certificate: CU
+	> GET /8003/r HTTP/1.1
+	> Host: localhost:9000
+	> User-Agent: curl/7.43.0
+	> Accept: */*
+	> Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJQYXNzd29yZCI6InRvb3RvbyIsIlVzZXIiOiIiLCJleHAiOjE0NTg5NDg2MTl9.quCwZ5vghVBucxMxQ4fSfD84yw_yPEp9qLGGQNcHNUk
+	>
+	< HTTP/1.1 200 OK
+	< Content-Length: 24
+	< Content-Type: text/plain; charset=utf-8
+	< Date: Thu, 24 Mar 2016 23:34:08 GMT
+	<
+	Hitting 8003 with /boo1
+	* Connection #0 to host localhost left intact
+	[jvd@laika webfront (master *%=)]$
+
+	[jvd@laika webfront (master=)]$ curl --insecure -H'Authorization: Bearer FAKETOKEN' -Lkvs  https://localhost:9000/8003/r *   Trying ::1...
+	* Connected to localhost (::1) port 9000 (#0)
+	* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+	* Server certificate: CU
+	> GET /8003/r HTTP/1.1
+	> Host: localhost:9000
+	> User-Agent: curl/7.43.0
+	> Accept: */*
+	> Authorization: Bearer FAKETOKEN
+	>
+	< HTTP/1.1 403 Forbidden
+	< Date: Thu, 24 Mar 2016 23:43:11 GMT
+	< Content-Length: 0
+	< Content-Type: text/plain; charset=utf-8
+	<
+	* Connection #0 to host localhost left intact
+	[jvd@laika webfront (master=)]$
+  
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/c6221c2e/traffic_ops/experimental/webfront/rules.json
----------------------------------------------------------------------
diff --git a/traffic_ops/experimental/webfront/rules.json b/traffic_ops/experimental/webfront/rules.json
new file mode 100644
index 0000000..fd6e792
--- /dev/null
+++ b/traffic_ops/experimental/webfront/rules.json
@@ -0,0 +1,32 @@
+[
+  {
+    "host": "local.com",
+    "path": "/login",
+    "forward": "localhost:8080",
+    "secure": false
+  },
+  {
+    "host": "local.com",
+    "path": "/a",
+    "forward": "localhost:8081",
+    "secure": true,
+    "capabilities": {
+    	"GET": "read-a",
+    	"POST": "write-a",
+    	"PUT": "write-a",
+    	"PATCH": "write-a"
+    }
+  },
+  {
+    "host": "local.com",
+    "path": "/b",
+    "forward": "localhost:8082",
+    "secure": true,
+    "capabilities": {
+    	"GET": "read-b",
+    	"POST": "write-b",
+    	"PUT": "write-b",
+    	"PATCH": "write-b"
+    }
+  }
+]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/c6221c2e/traffic_ops/experimental/webfront/server.key
----------------------------------------------------------------------
diff --git a/traffic_ops/experimental/webfront/server.key b/traffic_ops/experimental/webfront/server.key
new file mode 100644
index 0000000..b674147
--- /dev/null
+++ b/traffic_ops/experimental/webfront/server.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEA0g8TSrCJLfzMxzCB+zLo19NIrOAA2kR25vi8Hu+aM2PGxJbH
+FPSV0LG1HF3l/4QoG1JNYKuyXaPFDtPcefU7fQ7MqpAiBWj2HyIfnKyZyUX867Pg
+2CnSPTgMZyK3NMSnkAG+FSZzXKj6Vxjh0mKN1X+JRqyv1c/rWLg3RxecuVdq0D23
+l/1nZPWidiRp2XhUKeO3L3rLKu9tf80HJZ1TN3TsUxOGUgZHectN577qAaHr3KzD
+HVA4v7fmNRXQEUg4Iax8FxWIw0CQOFY9+lUqW1TKr7UmrqnzmhQmLFNBP5wuU1fI
+yz5HqNeR2VOt10VDBfYg7Wy08mFsSr3bhj9GMwIDAQABAoIBAQCC+H9QzG1bzQlp
+EKealg1zs/rWPvyJGrMAJAo3R7FfZVCjdlc+i5l1e7euriUfgaj4EALKyYL2u4u8
+SQBo0ix7NuUJW8C6ms0KcF5Bc6SXSBoAZDFG1hyNqwqgq5aLQiovscZwrX60QW+F
+KrByWpyQh2pyNG2V5IOa15EvtFs1e1f7+DCZ/KLjd5odxEZ93lLcDMQ4zmSl47uR
+I5rdixCQm8slUtRJxAB+nRck5htVGY8cwT6c+hx/GlZqY6xynMOwa9pC3zFegnr3
+nvHIiFEVu0CksaVBZNRe0S92r8VjHQPVRBa87Tsom6vJ0GxaeDfXchedrklCxMJh
+Y+QOPIVhAoGBAPgDxXGBD7VaUsBgimJKE1Q/inT2aZtwKrJi4l2fRE1Q0kOZvePv
+/LMiUZwcV0M+y45Y0VU2VXIdqAC1tYFhFfRKdmjCABFSidyhpIMJJZQrX3fFEDZq
+Vt95PrjlRC3+AVvVXVNWOxP4ObgorPzqXKtgxt10OltJfiLHHe0LF9nJAoGBANjS
+dUNU9OhCFA54MpfKtNLXvnYsxXigkN9rXAiOt9yd3x4l3o1EJs9t4a6stgzPaXDc
+ANkIPf1xsO9N0c+rikYQRo+JmbTaAQhac19NF7guTV6lHRa9bR4N4O14+62oXFEX
+3z5hp2Tr0/1qjp62ubDR8S7zY8ACsKiqd0msZ94bAoGAEy3XeuuMF24gsBfHG8q2
+q/Et99WGXSrTYnAbKTpDwebaG7gr4xCP7hpdTUEzzlNw0lUz+u70tJpuf3+Nxa+I
+TxfjCD7YWn6TgqhNXIS8jzS7cTugAVU/2pA5tXqlRxk5aayaRvOIJgcwD3m1xuko
+uWgGeOGgEachRfc37TjKY2ECgYAmDMDxYP5dqAL3Cxbt1m/nNF9DQ9YftiXWX3PW
+OJ2BhN773m9w4Q3ihwj862hDVT7OxH0NmUmvqX0AceqpBBSO+Ro45E/qEfvuaFko
+11GbS9zeCCHTtMhqZssbQYkBT7Nrs8HEo8SJjG02YrXGmpB5vE4UDDhsIMy5vLiU
+YEIWEwKBgQCXvBaNGJxPDu3//8yJJC4gFSWUxWYZ9x12Kke6AaUoeEn8RjTlaLRm
+Ol1ZiqHTSbRJQHjqmwKJAWSA3QX4S3ISeVOms7k30Bt02m4W0NgVRB2GxkFcnESH
+OxREDAQXG2lLP9O2HZPPHZ9aKKFM+M0GlOdQlqKk3AHPx33qCXLYtg==
+-----END RSA PRIVATE KEY-----

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/c6221c2e/traffic_ops/experimental/webfront/server.pem
----------------------------------------------------------------------
diff --git a/traffic_ops/experimental/webfront/server.pem b/traffic_ops/experimental/webfront/server.pem
new file mode 100644
index 0000000..c09c2ca
--- /dev/null
+++ b/traffic_ops/experimental/webfront/server.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDbzCCAlegAwIBAgIJAJozT3F7lmQwMA0GCSqGSIb3DQEBCwUAME4xCzAJBgNV
+BAYTAlVTMQswCQYDVQQIDAJDTzEPMA0GA1UEBwwGRGVudmVyMSEwHwYDVQQKDBhJ
+bnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYwMzI2MjIyODExWhcNMjYwMzI0
+MjIyODExWjBOMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ08xDzANBgNVBAcMBkRl
+bnZlcjEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkq
+hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0g8TSrCJLfzMxzCB+zLo19NIrOAA2kR2
+5vi8Hu+aM2PGxJbHFPSV0LG1HF3l/4QoG1JNYKuyXaPFDtPcefU7fQ7MqpAiBWj2
+HyIfnKyZyUX867Pg2CnSPTgMZyK3NMSnkAG+FSZzXKj6Vxjh0mKN1X+JRqyv1c/r
+WLg3RxecuVdq0D23l/1nZPWidiRp2XhUKeO3L3rLKu9tf80HJZ1TN3TsUxOGUgZH
+ectN577qAaHr3KzDHVA4v7fmNRXQEUg4Iax8FxWIw0CQOFY9+lUqW1TKr7Umrqnz
+mhQmLFNBP5wuU1fIyz5HqNeR2VOt10VDBfYg7Wy08mFsSr3bhj9GMwIDAQABo1Aw
+TjAdBgNVHQ4EFgQUdme3OnuvS+09/3Nkx1FS/4xgXoUwHwYDVR0jBBgwFoAUdme3
+OnuvS+09/3Nkx1FS/4xgXoUwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC
+AQEANNo5qASaoCc5/Utr10KIO/KoFesWL0v0bDIG3r0HaEp2gD44o884yQ8pFDNR
+bhUjs1SaHHcnGX5X3OGJVuP2vuz0pFaeKZJUawT1DTwaXQCTkRFw0Cb7oWdF6/FV
+pXuLBXWvEsu19jnrZGQbJw1lsOchPDNpp/h460JBWQOOYRfu3jSyBMwih40lEb+F
+1lA943aA2oGsDYJHnGRpUMLafe4gqcGWpfHUf2TaGe+tUSI7+JrhYLzjRyqTBdD3
+5Ss+eQo5tP0aOVMMCMCHmFfxgjBHGu4syQW5VYIZtzWMEKu2fEZCjkbV6XwVYVFL
+SKh7EgT1te7yUhfLSAF2969WHg==
+-----END CERTIFICATE-----

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/c6221c2e/traffic_ops/experimental/webfront/simpleserver/server.key
----------------------------------------------------------------------
diff --git a/traffic_ops/experimental/webfront/simpleserver/server.key b/traffic_ops/experimental/webfront/simpleserver/server.key
new file mode 100644
index 0000000..b674147
--- /dev/null
+++ b/traffic_ops/experimental/webfront/simpleserver/server.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEA0g8TSrCJLfzMxzCB+zLo19NIrOAA2kR25vi8Hu+aM2PGxJbH
+FPSV0LG1HF3l/4QoG1JNYKuyXaPFDtPcefU7fQ7MqpAiBWj2HyIfnKyZyUX867Pg
+2CnSPTgMZyK3NMSnkAG+FSZzXKj6Vxjh0mKN1X+JRqyv1c/rWLg3RxecuVdq0D23
+l/1nZPWidiRp2XhUKeO3L3rLKu9tf80HJZ1TN3TsUxOGUgZHectN577qAaHr3KzD
+HVA4v7fmNRXQEUg4Iax8FxWIw0CQOFY9+lUqW1TKr7UmrqnzmhQmLFNBP5wuU1fI
+yz5HqNeR2VOt10VDBfYg7Wy08mFsSr3bhj9GMwIDAQABAoIBAQCC+H9QzG1bzQlp
+EKealg1zs/rWPvyJGrMAJAo3R7FfZVCjdlc+i5l1e7euriUfgaj4EALKyYL2u4u8
+SQBo0ix7NuUJW8C6ms0KcF5Bc6SXSBoAZDFG1hyNqwqgq5aLQiovscZwrX60QW+F
+KrByWpyQh2pyNG2V5IOa15EvtFs1e1f7+DCZ/KLjd5odxEZ93lLcDMQ4zmSl47uR
+I5rdixCQm8slUtRJxAB+nRck5htVGY8cwT6c+hx/GlZqY6xynMOwa9pC3zFegnr3
+nvHIiFEVu0CksaVBZNRe0S92r8VjHQPVRBa87Tsom6vJ0GxaeDfXchedrklCxMJh
+Y+QOPIVhAoGBAPgDxXGBD7VaUsBgimJKE1Q/inT2aZtwKrJi4l2fRE1Q0kOZvePv
+/LMiUZwcV0M+y45Y0VU2VXIdqAC1tYFhFfRKdmjCABFSidyhpIMJJZQrX3fFEDZq
+Vt95PrjlRC3+AVvVXVNWOxP4ObgorPzqXKtgxt10OltJfiLHHe0LF9nJAoGBANjS
+dUNU9OhCFA54MpfKtNLXvnYsxXigkN9rXAiOt9yd3x4l3o1EJs9t4a6stgzPaXDc
+ANkIPf1xsO9N0c+rikYQRo+JmbTaAQhac19NF7guTV6lHRa9bR4N4O14+62oXFEX
+3z5hp2Tr0/1qjp62ubDR8S7zY8ACsKiqd0msZ94bAoGAEy3XeuuMF24gsBfHG8q2
+q/Et99WGXSrTYnAbKTpDwebaG7gr4xCP7hpdTUEzzlNw0lUz+u70tJpuf3+Nxa+I
+TxfjCD7YWn6TgqhNXIS8jzS7cTugAVU/2pA5tXqlRxk5aayaRvOIJgcwD3m1xuko
+uWgGeOGgEachRfc37TjKY2ECgYAmDMDxYP5dqAL3Cxbt1m/nNF9DQ9YftiXWX3PW
+OJ2BhN773m9w4Q3ihwj862hDVT7OxH0NmUmvqX0AceqpBBSO+Ro45E/qEfvuaFko
+11GbS9zeCCHTtMhqZssbQYkBT7Nrs8HEo8SJjG02YrXGmpB5vE4UDDhsIMy5vLiU
+YEIWEwKBgQCXvBaNGJxPDu3//8yJJC4gFSWUxWYZ9x12Kke6AaUoeEn8RjTlaLRm
+Ol1ZiqHTSbRJQHjqmwKJAWSA3QX4S3ISeVOms7k30Bt02m4W0NgVRB2GxkFcnESH
+OxREDAQXG2lLP9O2HZPPHZ9aKKFM+M0GlOdQlqKk3AHPx33qCXLYtg==
+-----END RSA PRIVATE KEY-----

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/c6221c2e/traffic_ops/experimental/webfront/simpleserver/server.pem
----------------------------------------------------------------------
diff --git a/traffic_ops/experimental/webfront/simpleserver/server.pem b/traffic_ops/experimental/webfront/simpleserver/server.pem
new file mode 100644
index 0000000..c09c2ca
--- /dev/null
+++ b/traffic_ops/experimental/webfront/simpleserver/server.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDbzCCAlegAwIBAgIJAJozT3F7lmQwMA0GCSqGSIb3DQEBCwUAME4xCzAJBgNV
+BAYTAlVTMQswCQYDVQQIDAJDTzEPMA0GA1UEBwwGRGVudmVyMSEwHwYDVQQKDBhJ
+bnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYwMzI2MjIyODExWhcNMjYwMzI0
+MjIyODExWjBOMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ08xDzANBgNVBAcMBkRl
+bnZlcjEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkq
+hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0g8TSrCJLfzMxzCB+zLo19NIrOAA2kR2
+5vi8Hu+aM2PGxJbHFPSV0LG1HF3l/4QoG1JNYKuyXaPFDtPcefU7fQ7MqpAiBWj2
+HyIfnKyZyUX867Pg2CnSPTgMZyK3NMSnkAG+FSZzXKj6Vxjh0mKN1X+JRqyv1c/r
+WLg3RxecuVdq0D23l/1nZPWidiRp2XhUKeO3L3rLKu9tf80HJZ1TN3TsUxOGUgZH
+ectN577qAaHr3KzDHVA4v7fmNRXQEUg4Iax8FxWIw0CQOFY9+lUqW1TKr7Umrqnz
+mhQmLFNBP5wuU1fIyz5HqNeR2VOt10VDBfYg7Wy08mFsSr3bhj9GMwIDAQABo1Aw
+TjAdBgNVHQ4EFgQUdme3OnuvS+09/3Nkx1FS/4xgXoUwHwYDVR0jBBgwFoAUdme3
+OnuvS+09/3Nkx1FS/4xgXoUwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC
+AQEANNo5qASaoCc5/Utr10KIO/KoFesWL0v0bDIG3r0HaEp2gD44o884yQ8pFDNR
+bhUjs1SaHHcnGX5X3OGJVuP2vuz0pFaeKZJUawT1DTwaXQCTkRFw0Cb7oWdF6/FV
+pXuLBXWvEsu19jnrZGQbJw1lsOchPDNpp/h460JBWQOOYRfu3jSyBMwih40lEb+F
+1lA943aA2oGsDYJHnGRpUMLafe4gqcGWpfHUf2TaGe+tUSI7+JrhYLzjRyqTBdD3
+5Ss+eQo5tP0aOVMMCMCHmFfxgjBHGu4syQW5VYIZtzWMEKu2fEZCjkbV6XwVYVFL
+SKh7EgT1te7yUhfLSAF2969WHg==
+-----END CERTIFICATE-----

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/c6221c2e/traffic_ops/experimental/webfront/simpleserver/simpleserver.go
----------------------------------------------------------------------
diff --git a/traffic_ops/experimental/webfront/simpleserver/simpleserver.go b/traffic_ops/experimental/webfront/simpleserver/simpleserver.go
new file mode 100644
index 0000000..e4baeb2
--- /dev/null
+++ b/traffic_ops/experimental/webfront/simpleserver/simpleserver.go
@@ -0,0 +1,25 @@
+package main
+
+import (
+	"io"
+	"log"
+	"net/http"
+	"os"
+)
+
+var Logger *log.Logger
+
+func hello(w http.ResponseWriter, r *http.Request) {
+	io.WriteString(w, "Hitting "+os.Args[1]+" with "+r.URL.Path+"\n")
+}
+
+func main() {
+	Logger = log.New(os.Stdout, " ", log.Ldate|log.Ltime|log.Lshortfile)
+	
+	http.HandleFunc("/", hello)
+
+	// Make sure you have the server.pem and server.key file. To gen self signed:
+	// openssl genrsa -out server.key 2048
+	// openssl req -new -x509 -key server.key -out server.pem -days 3650
+	Logger.Println(http.ListenAndServeTLS(":"+os.Args[1], "server.pem", "server.key", nil))
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/c6221c2e/traffic_ops/experimental/webfront/startfakes.sh
----------------------------------------------------------------------
diff --git a/traffic_ops/experimental/webfront/startfakes.sh b/traffic_ops/experimental/webfront/startfakes.sh
new file mode 100644
index 0000000..66675e5
--- /dev/null
+++ b/traffic_ops/experimental/webfront/startfakes.sh
@@ -0,0 +1,7 @@
+go run simpleserver/simpleserver.go  8001 &
+go run simpleserver/simpleserver.go  8002 &
+go run simpleserver/simpleserver.go  8003 &
+go run simpleserver/simpleserver.go  8004 &
+go run simpleserver/simpleserver.go  8005 &
+go run simpleserver/simpleserver.go  8006 &
+go run simpleserver/simpleserver.go  8007

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/c6221c2e/traffic_ops/experimental/webfront/webfront.config
----------------------------------------------------------------------
diff --git a/traffic_ops/experimental/webfront/webfront.config b/traffic_ops/experimental/webfront/webfront.config
new file mode 100644
index 0000000..f487dbd
--- /dev/null
+++ b/traffic_ops/experimental/webfront/webfront.config
@@ -0,0 +1,5 @@
+{
+	"httpsAddr": ":9000",
+	"ruleFile": "rules.json", 
+	"pollInterval": 60
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/c6221c2e/traffic_ops/experimental/webfront/webfront.go
----------------------------------------------------------------------
diff --git a/traffic_ops/experimental/webfront/webfront.go b/traffic_ops/experimental/webfront/webfront.go
new file mode 100644
index 0000000..76be08d
--- /dev/null
+++ b/traffic_ops/experimental/webfront/webfront.go
@@ -0,0 +1,293 @@
+//  Started with https://github.com/nf/webfront/blob/master/main.go
+// by Andrew Gerrand <ad...@golang.org>
+
+package main
+
+import (
+	"crypto/tls"
+	"encoding/json"
+	"fmt"
+	jwt "github.com/dgrijalva/jwt-go"
+	"log"
+	"net/http"
+	"net/http/httputil"
+	"os"
+	"path"
+	"strings"
+	"sync"
+	"time"
+)
+
+// TODO(amiry) - Handle token expiration
+// TODO(amiry) - Handle refresh tokens
+// TODO(amiry) - Where to keep the jwt secret? In the command line
+
+// Server implements an http.Handler that acts as a reverse proxy
+type Server struct {
+	mu    sync.RWMutex // guards the fields below
+	last  time.Time
+	rules []*Rule
+}
+
+// Rule represents a rule in a configuration file.
+type Rule struct {
+	Host          string              // to match against request Host header
+	Path          string              // to match against a path (start)
+	Forward       string              // reverse proxy map-to
+	Secure        bool                // protect with jwt?
+	Capabilities  map[string]string   // map HTTP methods to capabilitues  
+
+	handler http.Handler
+}
+
+type Claims struct {
+    Capabilities []string `json:"cap"`
+    jwt.StandardClaims
+}
+
+// Config holds the configuration of the server.
+type Config struct {
+	HTTPSAddr    string `json:"httpsAddr"`
+	RuleFile     string `json:"ruleFile"`
+	PollInterval int    `json:"pollInterval"`
+}
+
+var Logger *log.Logger
+
+func printUsage() {
+	exampleConfig := `{
+	"httpsAddr": ":9000",
+	"ruleFile": "rules.json",
+	"pollInterval": 60
+}`
+	fmt.Println("Usage: " + path.Base(os.Args[0]) + " config-file")
+	fmt.Println("")
+	fmt.Println("Example config-file:")
+	fmt.Println(exampleConfig)
+}
+
+func main() {
+
+	if len(os.Args) < 2 {
+		printUsage()
+		return
+	}
+
+	Logger = log.New(os.Stdout, " ", log.Ldate|log.Ltime|log.Lshortfile)
+
+	file, err := os.Open(os.Args[1])
+	if err != nil {
+		Logger.Println("Error opening config file:", err)
+		return
+	}
+	decoder := json.NewDecoder(file)
+	config := Config{}
+	err = decoder.Decode(&config)
+	if err != nil {
+		Logger.Println("Error reading config file:", err)
+		return
+	}
+	Logger.Println("Starting webfront...")
+	s, err := NewServer(config.RuleFile, time.Duration(config.PollInterval)*time.Second)
+	if err != nil {
+		Logger.Fatal(err)
+	}
+
+	// override the default so we can use self-signed certs on our microservices
+	// and use a self-signed cert in this server
+	http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
+	if _, err := os.Stat("server.pem"); os.IsNotExist(err) {
+		Logger.Fatal("server.pem file not found")
+	}
+	if _, err := os.Stat("server.key"); os.IsNotExist(err) {
+		Logger.Fatal("server.key file not found")
+	}
+	http.ListenAndServeTLS(config.HTTPSAddr, "server.pem", "server.key", s)
+}
+
+func validateToken(tokenString string) (*jwt.Token, error) {
+
+	tokenString = strings.Replace(tokenString, "Bearer ", "", 1)
+	token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
+		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
+			return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
+		}
+		return []byte("CAmeRAFiveSevenNineNine"), nil
+	})
+	return token, err
+}
+
+// NewServer constructs a Server that reads rules from file with a period
+// specified by poll.
+func NewServer(file string, poll time.Duration) (*Server, error) {
+	s := new(Server)
+	if err := s.loadRules(file); err != nil {
+		Logger.Fatal("Error loading rules file: ", err)
+	}
+	go s.refreshRules(file, poll)
+	return s, nil
+}
+
+// ServeHTTP matches the Request with a Rule and, if found, serves the
+// request with the Rule's handler. If the rule's secure field is true, it will
+// only allow access if the request has a valid JWT bearer token.
+func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+
+	rule := s.getRule(r)
+	if rule == nil {
+		Logger.Printf("%v %v No mapping in rules file!", r.Method, r.URL.RequestURI())
+		http.Error(w, "Not found", http.StatusNotFound)
+		return
+	}
+
+	isAuthorized := false
+
+	if rule.Secure {
+		tokenValid := false
+		token, err := validateToken(r.Header.Get("Authorization"))
+
+		if err == nil {
+			tokenValid = true
+		} else {
+			Logger.Println("Token Error:", err.Error())
+		}
+
+		if !tokenValid {
+			Logger.Printf("%v %v Valid token required, but none found!", r.Method, r.URL.RequestURI())
+			w.WriteHeader(http.StatusForbidden)
+			return
+		}
+
+		claims, ok := token.Claims.(*Claims)
+		if !ok {
+			Logger.Printf("%v %v Valid token found, but cannot parse claims!", r.Method, r.URL.RequestURI())
+			w.WriteHeader(http.StatusForbidden)
+			return
+		}
+
+		// Authorization: Check is the list of capabilities in the token's claims contains the reqired capability
+		// that is listed in the rule
+		Logger.Printf("Required capabilities %v", rule.Capabilities)
+		for _, c := range claims.Capabilities {
+        	if c == rule.Capabilities[r.Method] {
+				isAuthorized = true
+				break
+			}
+        }
+
+		Logger.Printf("%v %v Valid token. Subject=%v, ExpiresAt=%v, Capabilities=%v, Required=%v, Authorized=%v", 
+			r.Method, r.URL.RequestURI(), claims.Subject, claims.ExpiresAt, claims.Capabilities, 
+			rule.Capabilities[r.Method], isAuthorized)
+
+	} else {
+		isAuthorized = true
+	}
+
+	if isAuthorized {
+		if h := rule.handler; h != nil {
+			h.ServeHTTP(w, r)
+			return
+		}
+	}
+
+	http.Error(w, "Not Authorized", http.StatusUnauthorized)
+	return
+}
+
+func rejectNoToken(handler http.Handler) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		w.WriteHeader(http.StatusForbidden)
+	}
+}
+
+func (s *Server) getRule(req *http.Request) *Rule {
+	s.mu.RLock()
+	defer s.mu.RUnlock()
+
+	h := req.Host
+	p := req.URL.Path
+
+	// Some clients include a port in the request host; strip it.
+	if i := strings.Index(h, ":"); i >= 0 {
+		h = h[:i]
+	}
+
+	for _, r := range s.rules {
+		if strings.HasPrefix(p, r.Path) {
+			// Logger.Printf("Found rule")
+			return r
+		}
+	}
+
+	// Logger.Printf("Rule not found")
+	return nil
+}
+
+// refreshRules polls file periodically and refreshes the Server's rule
+// set if the file has been modified.
+func (s *Server) refreshRules(file string, poll time.Duration) {
+	for {
+		// Logger.Printf("loading rule file")
+		if err := s.loadRules(file); err != nil {
+			Logger.Println(file, ":", err)
+		}
+		time.Sleep(poll)
+	}
+}
+
+// loadRules tests whether file has been modified since its last invocation
+// and, if so, loads the rule set from file.
+func (s *Server) loadRules(file string) error {
+	fi, err := os.Stat(file)
+	if err != nil {
+		return err
+	}
+	mtime := fi.ModTime()
+	if !mtime.After(s.last) && s.rules != nil {
+		return nil // no change
+	}
+	rules, err := parseRules(file)
+	if err != nil {
+		return err
+	}
+	s.mu.Lock()
+	s.last = mtime
+	s.rules = rules
+	s.mu.Unlock()
+	return nil
+}
+
+// parseRules reads rule definitions from file, constructs the Rule handlers,
+// and returns the resultant Rules.
+func parseRules(file string) ([]*Rule, error) {
+	f, err := os.Open(file)
+	if err != nil {
+		return nil, err
+	}
+	defer f.Close()
+	var rules []*Rule
+	if err := json.NewDecoder(f).Decode(&rules); err != nil {
+		return nil, err
+	}
+	for _, r := range rules {
+		r.handler = makeHandler(r)
+		if r.handler == nil {
+			Logger.Printf("Bad rule: %#v", r)
+		}
+	}
+	return rules, nil
+}
+
+// makeHandler constructs the appropriate Handler for the given Rule.
+func makeHandler(r *Rule) http.Handler {
+	if h := r.Forward; h != "" {
+		return &httputil.ReverseProxy{
+			Director: func(req *http.Request) {
+				req.URL.Scheme = "https"
+				req.URL.Host = h
+				// req.URL.Path = "/boo1" // TODO JvD - regex to change path here
+			},
+		}
+	}
+	return nil
+}



[5/5] incubator-trafficcontrol git commit: This closes #313

Posted by jv...@apache.org.
This closes #313


Project: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/commit/4d8182f4
Tree: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/tree/4d8182f4
Diff: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/diff/4d8182f4

Branch: refs/heads/master
Commit: 4d8182f4e4311f1db72fc09e139eda580261725a
Parents: 844f765
Author: Jan van Doorn <ja...@cable.comcast.com>
Authored: Sat Mar 11 11:09:22 2017 -0700
Committer: Jan van Doorn <ja...@cable.comcast.com>
Committed: Sat Mar 11 11:09:22 2017 -0700

----------------------------------------------------------------------

----------------------------------------------------------------------



[4/5] incubator-trafficcontrol git commit: update auth service to authenticate user against tm_users. add user's capabilities to jwt claims. capabilities are currently hard coded because role tables are not ready yet. webfront authorize user according to

Posted by jv...@apache.org.
update auth service to authenticate user against tm_users. add user's capabilities to jwt claims. capabilities are currently hard coded because role tables are not ready yet. webfront authorize user according to capabilities. jwt signing secret is passed to both services on command line


Project: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/commit/610f69c6
Tree: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/tree/610f69c6
Diff: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/diff/610f69c6

Branch: refs/heads/master
Commit: 610f69c6c730fd5b27c5b31ca74d44ca12cf6c9b
Parents: c6221c2
Author: Amir Yeshurun <am...@qwilt.com>
Authored: Sun Feb 26 23:29:40 2017 +0200
Committer: Jan van Doorn <ja...@cable.comcast.com>
Committed: Sat Mar 11 11:06:09 2017 -0700

----------------------------------------------------------------------
 traffic_ops/experimental/auth/README.md         |   9 ++
 traffic_ops/experimental/auth/auth.config       |  14 +-
 traffic_ops/experimental/auth/auth.go           | 115 +++++++++-------
 traffic_ops/experimental/webfront/README.md     | 132 ++++++-------------
 traffic_ops/experimental/webfront/rules.json    |  58 ++++----
 .../experimental/webfront/webfront.config       |   8 +-
 traffic_ops/experimental/webfront/webfront.go   |  35 ++---
 7 files changed, 181 insertions(+), 190 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/610f69c6/traffic_ops/experimental/auth/README.md
----------------------------------------------------------------------
diff --git a/traffic_ops/experimental/auth/README.md b/traffic_ops/experimental/auth/README.md
new file mode 100644
index 0000000..1e86579
--- /dev/null
+++ b/traffic_ops/experimental/auth/README.md
@@ -0,0 +1,9 @@
+
+A simple authentication server written in go that authenticates user agains the `tm_user` table and returns a jwt representing the user, incl. its API access capabilities, derived from the user's role.
+
+* To run:
+`go run auth.go auth.config my-secret`
+`secret` is used for jwt signing
+
+* To login:
+`curl --insecure -X POST -Lkvs --header "Content-Type:application/json" https://localhost:9004/login -d'{"username":"username", "password":"password"}'`

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/610f69c6/traffic_ops/experimental/auth/auth.config
----------------------------------------------------------------------
diff --git a/traffic_ops/experimental/auth/auth.config b/traffic_ops/experimental/auth/auth.config
index 642923e..2c4dfa5 100644
--- a/traffic_ops/experimental/auth/auth.config
+++ b/traffic_ops/experimental/auth/auth.config
@@ -1,8 +1,8 @@
 {
-	"dbName":"amiry",
-	"dbUser":"amiry",
-	"dbPassword":"blabla",
-	"dbServer":"localhost",
-	"dbPort":5432,
-	"listenerPort":"8080"
-}
+	"db-name":     "to_development",
+	"db-user":     "username",
+	"db-password": "password",
+	"db-server":   "localhost",
+	"db-port":     5432,
+	"listen-port": 9004
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/610f69c6/traffic_ops/experimental/auth/auth.go
----------------------------------------------------------------------
diff --git a/traffic_ops/experimental/auth/auth.go b/traffic_ops/experimental/auth/auth.go
index 937124f..0cedfef 100644
--- a/traffic_ops/experimental/auth/auth.go
+++ b/traffic_ops/experimental/auth/auth.go
@@ -1,6 +1,7 @@
 package main
 
 import (
+	"crypto/sha1"
 	"encoding/json"
 	"fmt"
 	jwt "github.com/dgrijalva/jwt-go"
@@ -11,24 +12,28 @@ import (
 	"net/http"
 	"os"
 	"path"
+	"strconv"
 	"time"
 )
 
 // Config holds the configuration of the server.
 type Config struct {
-	DbName       string `json:"dbName"`
-	DbUser       string `json:"dbUser"`
-	DbPassword   string `json:"dbPassword"`
-	DbServer     string `json:"dbServer,omitempty"`
-	DbPort       uint   `json:"dbPort,omitempty"`
-	ListenerPort string `json:"listenerPort"`
+	DbName      string `json:"db-name"`
+	DbUser      string `json:"db-user"`
+	DbPassword  string `json:"db-password"`
+	DbServer    string `json:"db-server"`
+	DbPort      uint   `json:"db-port"`
+	ListenPort  uint   `json:"listen-port"`
 }
 
-type User struct {
-	Username  string `db:"username" json:"username"`
-	FirstName string `db:"first_name" json:"firstName,omitempty"`
-	LastName  string `db:"last_name" json:"lastName,omitempty"`
-	Password  string `db:"password" json:"password"`
+type Login struct {
+	Username    string `json:"username"`
+	Password    string `json:"password"`
+}
+
+type TmUser struct {
+	Role        uint   `db:"role"`
+	Password    string `db:"local_passwd"`
 }
 
 type Claims struct {
@@ -42,30 +47,29 @@ type TokenResponse struct {
 
 var db *sqlx.DB // global and simple
 
+var Logger *log.Logger
+
 func printUsage() {
 	exampleConfig := `{
-	"dbName":"my-db",
-	"dbUser":"my-user",
-	"dbPassword":"secret",
-	"dbServer":"localhost",
-	"dbPort":5432,
-	"listenerPort":"8080"
+	"db_name":     "to_development",
+	"db_user":     "username",
+	"db_password": "password",
+	"db_server":   "localhost",
+	"db_port":     5432,
+	"listen_port": 9004
 }`
-	Logger.Println("Usage: " + path.Base(os.Args[0]) + " configfile")
-	Logger.Println("")
-	Logger.Println("Example config file:")
-	Logger.Println(exampleConfig)
+	fmt.Println("Usage: " + path.Base(os.Args[0]) + " config-file secret")
+	fmt.Println("")
+	fmt.Println("Example config file:")
+	fmt.Println(exampleConfig)
 }
 
-var Logger *log.Logger
-
 func main() {
-	if len(os.Args) < 2 {
+	if len(os.Args) < 3 {
 		printUsage()
 		return
 	}
 
-	// log.SetOutput(os.Stdout)
 	Logger = log.New(os.Stdout, " ", log.Ldate|log.Ltime|log.Lshortfile)
 
 	file, err := os.Open(os.Args[1])
@@ -73,6 +77,7 @@ func main() {
 		Logger.Println("Error opening config file:", err)
 		return
 	}
+
 	decoder := json.NewDecoder(file)
 	config := Config{}
 	err = decoder.Decode(&config)
@@ -87,15 +92,18 @@ func main() {
 		return
 	}
 
-	http.HandleFunc("/", handler)
+	http.HandleFunc("/login", handler)
+	
 	if _, err := os.Stat("server.pem"); os.IsNotExist(err) {
 		Logger.Fatal("server.pem file not found")
 	}
+
 	if _, err := os.Stat("server.key"); os.IsNotExist(err) {
 		Logger.Fatal("server.key file not found")
 	}
-	Logger.Printf("Starting server on port " + config.ListenerPort + "...")
-	Logger.Fatal(http.ListenAndServeTLS(":"+config.ListenerPort, "server.pem", "server.key", nil))
+
+	Logger.Printf("Starting server on port %d...", config.ListenPort)
+	Logger.Fatal(http.ListenAndServeTLS(":" + strconv.Itoa(int(config.ListenPort)), "server.pem", "server.key", nil))
 }
 
 func InitializeDatabase(username, password, dbname, server string, port uint) (*sqlx.DB, error) {
@@ -114,59 +122,78 @@ func handler(w http.ResponseWriter, r *http.Request) {
 	Logger.Println(r.Method, r.URL.Scheme, r.Host, r.URL.RequestURI())
 
 	if r.Method == "POST" {
-		var u User
-		userlist := []User{}
+		var login Login
+		tmUserlist := []TmUser{}
 		body, err := ioutil.ReadAll(r.Body)
-		log.Println(string(body))
 		if err != nil {
 			Logger.Println("Error reading body: ", err.Error())
 			http.Error(w, "Error reading body: "+err.Error(), http.StatusBadRequest)
 			return
 		}
-		err = json.Unmarshal(body, &u)
+		
+		err = json.Unmarshal(body, &login)
 		if err != nil {
-			Logger.Println("Error unmarshalling JSON: ", err.Error())
+			Logger.Println("Invalid JSON: ", err.Error())
 			http.Error(w, "Invalid JSON: "+err.Error(), http.StatusBadRequest)
 			return
 		}
-		stmt, err := db.PrepareNamed("SELECT * FROM users WHERE username=:username")
-		err = stmt.Select(&userlist, u)
+		
+		stmt, err := db.PrepareNamed("SELECT role,local_passwd FROM tm_user WHERE username=:username")
 		if err != nil {
-			Logger.Println(err.Error())
+			Logger.Println("Database error: ", err.Error())
+			http.Error(w, "Database error: "+err.Error(), http.StatusInternalServerError)
+			return
+		}
+
+		err = stmt.Select(&tmUserlist, login)
+		if err != nil {
+			Logger.Println("Database error: ", err.Error())
 			http.Error(w, "Database error: "+err.Error(), http.StatusInternalServerError)
 			return
 		}
-		if len(userlist) == 0 || userlist[0].Password != u.Password {
-			http.Error(w, "Invalid username/password ", http.StatusUnauthorized)
+
+    	hasher := sha1.New()
+    	hasher.Write([]byte(login.Password))
+    	hashedPassword := fmt.Sprintf("%x", hasher.Sum(nil))
+
+		if len(tmUserlist) == 0 || tmUserlist[0].Password != string(hashedPassword) {
+			Logger.Printf("Invalid username/password, username %s", login.Username)
+			http.Error(w, "Invalid username/password", http.StatusUnauthorized)
 			return
 		}
 
+		Logger.Printf("User %s authenticated", login.Username)
+
 		claims := Claims {
-	        []string{"read-a", "write-a", "read-b"}, // TODO(amiry) - Read from DB
+	        []string{"read-ds", "write-ds", "read-cg"},	// TODO(amiry) - Adding hardcoded capabilities as a POC. 
+	        											// Need to read from TO role tables when tables are ready
 	        jwt.StandardClaims {
-	        	Subject: u.Username,
-	            ExpiresAt: time.Now().Add(time.Hour * 24).Unix(), // TODO(amiry) - Use shorter expiration
+	        	Subject: login.Username,
+	            ExpiresAt: time.Now().Add(time.Hour * 24).Unix(),	// TODO(amiry) - We will need to use shorter expiration, 
+	            													// and use refresh tokens to extend access
 	        },
 	    }
 
 		token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
 
-		tokenString, err := token.SignedString([]byte("CAmeRAFiveSevenNineNine")) // TODO(amiry) - Where to keep secret?
+		tokenString, err := token.SignedString([]byte(os.Args[2]))
 		if err != nil {
 			Logger.Println(err.Error())
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 			return
 		}
+
 		js, err := json.Marshal(TokenResponse{Token: tokenString})
 		if err != nil {
 			Logger.Println(err.Error())
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 			return
 		}
-		// w.WriteHeader(http.StatusOK)
+
 		w.Header().Set("Content-Type", "application/json")
 		w.Write(js)
 		return
 	}
+
 	http.Error(w, r.Method+" "+r.URL.Path+" not valid for this microservice", http.StatusNotFound)
-}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/610f69c6/traffic_ops/experimental/webfront/README.md
----------------------------------------------------------------------
diff --git a/traffic_ops/experimental/webfront/README.md b/traffic_ops/experimental/webfront/README.md
index 041a219..576f86e 100644
--- a/traffic_ops/experimental/webfront/README.md
+++ b/traffic_ops/experimental/webfront/README.md
@@ -1,98 +1,52 @@
-This application - webfront is a reverse proxy written in go that can front any number of microservices. It uses a rules file to map from requested host/path to microservice host/port/path.  Example rule file:
-
-   
-    [
-		{"Host": "local.com", "Path" : "/8001", "Forward": "localhost:8001"},
-		{"Host": "local.com", "Path" : "/8002", "Forward": "localhost:8002"},
-		{"Host": "local.com", "Path" : "/8003", "Forward": "localhost:8003"},
-		{"Host": "local.com", "Path" : "/8004", "Forward": "localhost:8004"},
-		{"Host": "local.com", "Path" : "/8005", "Forward": "localhost:8005"},
-		{"Host": "local.com", "Path" : "/8006", "Forward": "localhost:8006"},
-		{"Host": "local.com", "Path" : "/8007", "Forward": "localhost:8007"}
+A reverse proxy written in go that can front any number of microservices. It uses a rules file to map from requested host/path to microservice host/port/path.  Example rule file:
+
+```json
+	[
+	  {
+	    "host": "domain.com",
+	    "path": "/login",
+	    "forward": "localhost:9004",
+	    "secure": false
+	  },
+	  {
+	    "host": "domain.com",
+	    "path": "/ds/",
+	    "forward": "localhost:8081",
+	    "secure": true,
+	    "capabilities": {
+	        "GET": "read-ds",
+	        "POST": "write-ds",
+	        "PUT": "write-ds",
+	        "PATCH": "write-ds"
+	    }
+	  },
+	  {
+	    "host": "domain.com",
+	    "path": "/cachegroups/",
+	    "forward": "localhost:8082",
+	    "secure": true,
+	    "capabilities": {
+	        "GET": "read-cg",
+	        "POST": "write-cg",
+	        "PUT": "write-cg",
+	        "PATCH": "write-cg"
+	    }
+	  }
 	]
+```
 
+Note: Access "capabilities" are set in the rule file as a workaround, until TO DB tables are ready.
 
 No restart is needed to re-read the rule file and apply; within 60 seconds of a change in the file, it will pick up the new mappings.
 
-To run
-
-	go run webfront.go -rules=rules.json -https=:9000 -https_cert=server.pem -https_key=server.key 
-
-(or compile a binary, and run that)
-
-To get a token:
-
-	curl --insecure -Lkvs --header "Content-Type:application/json" -XPOST https://localhost:9000/login -d'{"username":"jvd", "password":"tootoo"}'
-   
-in my case that returned: 
-
-	{"Token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJQYXNzd29yZCI6InRvb3RvbyIsIlVzZXIiOiIiLCJleHAiOjE0NTg5NDg2MTl9.quCwZ5vghVBucxMxQ4fSfD84yw_yPEp9qLGGQNcHNUk"}``
-   
- Example:
-  
-	[jvd@laika webfront (master *=)]$ curl --insecure -Lkvs --header "Content-Type:application/json" -XPOST https://localhost:9000/login -d'{"username":"jvd", "password":"tootoo"}'
-	*   Trying ::1...
-	* Connected to localhost (::1) port 9000 (#0)
-	* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
-	* Server certificate: CU
-	> POST /login HTTP/1.1
-	> Host: localhost:9000
-	> User-Agent: curl/7.43.0
-	> Accept: */*
-	> Content-Type:application/json
-	> Content-Length: 39
-	>
-	* upload completely sent off: 39 out of 39 bytes
-	< HTTP/1.1 200 OK
-	< Content-Type: application/json
-	< Date: Thu, 24 Mar 2016 23:30:19 GMT
-	< Content-Length: 157
-	<
-	* Connection #0 to host localhost left intact
-	{"Token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJQYXNzd29yZCI6InRvb3RvbyIsIlVzZXIiOiIiLCJleHAiOjE0NTg5NDg2MTl9.quCwZ5vghVBucxMxQ4fSfD84yw_yPEp9qLGGQNcHNUk"}[jvd@laika webfront (master *=)]$
- 
- * To use a token: 
-
-	curl --insecure -H'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJQYXNzd29yZCI6InRvb3RvbyIsIlVzZXIiOiIiLCJleHAiOjE0NTg5NDg2MTl9.quCwZ5vghVBucxMxQ4fSfD84yw_yPEp9qLGGQNcHNUk' -Lkvs  https://localhost:9000/8003/r
+* To run:
+`go run webfront.go webfront.config my-secret`
+`secret` is used for jwt signing
 
-Example:
 
+* To login:
+`curl -X POST --insecure -Lkvs --header "Content-Type:application/json" https://localhost:9004/login -d'{"username":"foo", "password":"bar"}'`
    
-    [jvd@laika webfront (master *%=)]$ curl --insecure -H'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJQYXNzd29yZCI6InRvb3RvbyIsIlVzZXIiOiIiLCJleHAiOjE0NTg5NDg2MTl9.quCwZ5vghVBucxMxQ4fSfD84yw_yPEp9qLGGQNcHNUk' -Lkvs  https://localhost:9000/8003/r
-	*   Trying ::1...
-	* Connected to localhost (::1) port 9000 (#0)
-	* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
-	* Server certificate: CU
-	> GET /8003/r HTTP/1.1
-	> Host: localhost:9000
-	> User-Agent: curl/7.43.0
-	> Accept: */*
-	> Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJQYXNzd29yZCI6InRvb3RvbyIsIlVzZXIiOiIiLCJleHAiOjE0NTg5NDg2MTl9.quCwZ5vghVBucxMxQ4fSfD84yw_yPEp9qLGGQNcHNUk
-	>
-	< HTTP/1.1 200 OK
-	< Content-Length: 24
-	< Content-Type: text/plain; charset=utf-8
-	< Date: Thu, 24 Mar 2016 23:34:08 GMT
-	<
-	Hitting 8003 with /boo1
-	* Connection #0 to host localhost left intact
-	[jvd@laika webfront (master *%=)]$
+* To use a token:
+`curl --insecure -H'Authorization: Bearer <token>' -Lkvs  https://localhost:8080/ds/`
 
-	[jvd@laika webfront (master=)]$ curl --insecure -H'Authorization: Bearer FAKETOKEN' -Lkvs  https://localhost:9000/8003/r *   Trying ::1...
-	* Connected to localhost (::1) port 9000 (#0)
-	* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
-	* Server certificate: CU
-	> GET /8003/r HTTP/1.1
-	> Host: localhost:9000
-	> User-Agent: curl/7.43.0
-	> Accept: */*
-	> Authorization: Bearer FAKETOKEN
-	>
-	< HTTP/1.1 403 Forbidden
-	< Date: Thu, 24 Mar 2016 23:43:11 GMT
-	< Content-Length: 0
-	< Content-Type: text/plain; charset=utf-8
-	<
-	* Connection #0 to host localhost left intact
-	[jvd@laika webfront (master=)]$
-  
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/610f69c6/traffic_ops/experimental/webfront/rules.json
----------------------------------------------------------------------
diff --git a/traffic_ops/experimental/webfront/rules.json b/traffic_ops/experimental/webfront/rules.json
index fd6e792..46d9f28 100644
--- a/traffic_ops/experimental/webfront/rules.json
+++ b/traffic_ops/experimental/webfront/rules.json
@@ -1,32 +1,32 @@
 [
-  {
-    "host": "local.com",
-    "path": "/login",
-    "forward": "localhost:8080",
-    "secure": false
-  },
-  {
-    "host": "local.com",
-    "path": "/a",
-    "forward": "localhost:8081",
-    "secure": true,
-    "capabilities": {
-    	"GET": "read-a",
-    	"POST": "write-a",
-    	"PUT": "write-a",
-    	"PATCH": "write-a"
+    {
+        "host": "domain.com",
+        "path": "/login",
+        "forward": "localhost:9004",
+        "secure": false
+    },
+    {
+        "host": "domain.com",
+        "path": "/ds/",
+        "forward": "localhost:8081",
+        "secure": true,
+        "capabilities": {
+            "GET": "read-ds",
+            "POST": "write-ds",
+            "PUT": "write-ds",
+            "PATCH": "write-ds"
+        }
+    },
+    {
+        "host": "domain.com",
+        "path": "/cachegroups/",
+        "forward": "localhost:8082",
+        "secure": true,
+        "capabilities": {
+            "GET": "read-cg",
+            "POST": "write-cg",
+            "PUT": "write-cg",
+            "PATCH": "write-cg"
+        }
     }
-  },
-  {
-    "host": "local.com",
-    "path": "/b",
-    "forward": "localhost:8082",
-    "secure": true,
-    "capabilities": {
-    	"GET": "read-b",
-    	"POST": "write-b",
-    	"PUT": "write-b",
-    	"PATCH": "write-b"
-    }
-  }
 ]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/610f69c6/traffic_ops/experimental/webfront/webfront.config
----------------------------------------------------------------------
diff --git a/traffic_ops/experimental/webfront/webfront.config b/traffic_ops/experimental/webfront/webfront.config
index f487dbd..b54f3df 100644
--- a/traffic_ops/experimental/webfront/webfront.config
+++ b/traffic_ops/experimental/webfront/webfront.config
@@ -1,5 +1,5 @@
 {
-	"httpsAddr": ":9000",
-	"ruleFile": "rules.json", 
-	"pollInterval": 60
-}
+	"rule-file": "rules.json",
+	"poll-interval": 60,
+	"listen-port": 8080
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/610f69c6/traffic_ops/experimental/webfront/webfront.go
----------------------------------------------------------------------
diff --git a/traffic_ops/experimental/webfront/webfront.go b/traffic_ops/experimental/webfront/webfront.go
index 76be08d..247ea24 100644
--- a/traffic_ops/experimental/webfront/webfront.go
+++ b/traffic_ops/experimental/webfront/webfront.go
@@ -13,14 +13,13 @@ import (
 	"net/http/httputil"
 	"os"
 	"path"
+	"strconv"
 	"strings"
 	"sync"
 	"time"
 )
 
-// TODO(amiry) - Handle token expiration
 // TODO(amiry) - Handle refresh tokens
-// TODO(amiry) - Where to keep the jwt secret? In the command line
 
 // Server implements an http.Handler that acts as a reverse proxy
 type Server struct {
@@ -47,20 +46,20 @@ type Claims struct {
 
 // Config holds the configuration of the server.
 type Config struct {
-	HTTPSAddr    string `json:"httpsAddr"`
-	RuleFile     string `json:"ruleFile"`
-	PollInterval int    `json:"pollInterval"`
+	RuleFile     string `json:"rule-file"`
+	PollInterval int    `json:"poll-interval"`
+	ListenPort   int    `json:"listen-port"`
 }
 
 var Logger *log.Logger
 
 func printUsage() {
 	exampleConfig := `{
-	"httpsAddr": ":9000",
-	"ruleFile": "rules.json",
-	"pollInterval": 60
+	"listen-port":   9000,
+	"rule-file":     "rules.json",
+	"poll-interval": 60
 }`
-	fmt.Println("Usage: " + path.Base(os.Args[0]) + " config-file")
+	fmt.Println("Usage: " + path.Base(os.Args[0]) + " config-file secret")
 	fmt.Println("")
 	fmt.Println("Example config-file:")
 	fmt.Println(exampleConfig)
@@ -68,7 +67,7 @@ func printUsage() {
 
 func main() {
 
-	if len(os.Args) < 2 {
+	if len(os.Args) < 3 {
 		printUsage()
 		return
 	}
@@ -80,6 +79,7 @@ func main() {
 		Logger.Println("Error opening config file:", err)
 		return
 	}
+
 	decoder := json.NewDecoder(file)
 	config := Config{}
 	err = decoder.Decode(&config)
@@ -87,7 +87,7 @@ func main() {
 		Logger.Println("Error reading config file:", err)
 		return
 	}
-	Logger.Println("Starting webfront...")
+
 	s, err := NewServer(config.RuleFile, time.Duration(config.PollInterval)*time.Second)
 	if err != nil {
 		Logger.Fatal(err)
@@ -102,7 +102,9 @@ func main() {
 	if _, err := os.Stat("server.key"); os.IsNotExist(err) {
 		Logger.Fatal("server.key file not found")
 	}
-	http.ListenAndServeTLS(config.HTTPSAddr, "server.pem", "server.key", s)
+
+	Logger.Printf("Starting webfront on port %d...", config.ListenPort)
+	Logger.Fatal(http.ListenAndServeTLS(":" + strconv.Itoa(int(config.ListenPort)), "server.pem", "server.key", s))
 }
 
 func validateToken(tokenString string) (*jwt.Token, error) {
@@ -112,7 +114,7 @@ func validateToken(tokenString string) (*jwt.Token, error) {
 		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
 			return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
 		}
-		return []byte("CAmeRAFiveSevenNineNine"), nil
+		return []byte(os.Args[2]), nil
 	})
 	return token, err
 }
@@ -165,9 +167,8 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 			return
 		}
 
-		// Authorization: Check is the list of capabilities in the token's claims contains the reqired capability
-		// that is listed in the rule
-		Logger.Printf("Required capabilities %v", rule.Capabilities)
+		// Authorization: Check is the list of capabilities in the token's claims contains 
+		// the reqired capability that is listed in the rule
 		for _, c := range claims.Capabilities {
         	if c == rule.Capabilities[r.Method] {
 				isAuthorized = true
@@ -290,4 +291,4 @@ func makeHandler(r *Rule) http.Handler {
 		}
 	}
 	return nil
-}
+}
\ No newline at end of file