Skip to content
This repository has been archived by the owner on Jan 31, 2018. It is now read-only.

Commit

Permalink
Move webhook handlers into their own package
Browse files Browse the repository at this point in the history
  • Loading branch information
dims committed Jul 28, 2017
1 parent 91e46b3 commit 42a3075
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 116 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ depend-update: work
cd $(DEST) && glide update

build: work
cd $(DEST) && mkdir bin && go build -o bin/k8s-keystone-auth main.go
cd $(DEST) && mkdir -p $(DEST)/bin && go build -o $(DEST)/bin/k8s-keystone-auth main.go

test: unit functional

Expand Down
119 changes: 4 additions & 115 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,134 +15,23 @@ limitations under the License.
package main

import (
"encoding/json"
"flag"
"fmt"
"log"
"net/http"

"github.com/dims/k8s-keystone-auth/pkg/authenticator/token/keystone"
"github.com/dims/k8s-keystone-auth/pkg/identity/webhook"
"k8s.io/apiserver/pkg/authentication/authenticator"
"k8s.io/apiserver/pkg/authorization/authorizer"
)

type userInfo struct {
Username string `json:"username"`
UID string `json:"uid"`
Groups []string `json:"groups"`
Extra map[string][]string `json:"extra"`
}
type status struct {
Authenticated bool `json:"authenticated"`
User userInfo `json:"user"`
}

type webhookHandler struct {
authenticator authenticator.Token
authorizer authorizer.Authorizer
}

func webhookServer(authenticator authenticator.Token, authorizer authorizer.Authorizer) http.Handler {
return &webhookHandler{
authenticator: authenticator,
authorizer: authorizer,
}
}

func (h *webhookHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
var data map[string]interface{}
decoder := json.NewDecoder(r.Body)
defer r.Body.Close()
err := decoder.Decode(&data)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

var apiVersion = data["apiVersion"].(string)
var kind = data["kind"].(string)

if apiVersion != "authentication.k8s.io/v1beta1" && apiVersion != "authorization.k8s.io/v1beta1" {
http.Error(w, fmt.Sprintf("unknown apiVersion %q", apiVersion),
http.StatusBadRequest)
return
}
if kind == "TokenReview" {
var token = data["spec"].(map[string]interface{})["token"].(string)
h.authenticateToken(w, r, token, data)
} else if kind == "SubjectAccessReview" {
h.authorizeToken(w, r, data)
} else {
http.Error(w, fmt.Sprintf("unknown kind/apiVersion %q %q", kind, apiVersion),
http.StatusBadRequest)
}
}

func (h *webhookHandler) authenticateToken(w http.ResponseWriter, r *http.Request, token string, data map[string]interface{}) {
user, authenticated, err := h.authenticator.AuthenticateToken(token)

if !authenticated {
var response status
response.Authenticated = false
data["status"] = response

output, err := json.MarshalIndent(data, "", " ")
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusUnauthorized)
w.Write(output)
return
}

var info userInfo
info.Username = user.GetName()
info.UID = user.GetUID()
info.Groups = user.GetGroups()
info.Extra = user.GetExtra()

var response status
response.Authenticated = true
response.User = info

data["status"] = response

output, err := json.MarshalIndent(data, "", " ")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
return &webhook.WebhookHandler{
Authenticator: authenticator,
Authorizer: authorizer,
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(output)
}

func (h *webhookHandler) authorizeToken(w http.ResponseWriter, r *http.Request, data map[string]interface{}) {
fmt.Printf("authorizeToken data : %#v\n", data)
temp, _ := json.MarshalIndent(data, "", " ")
fmt.Printf("REQUEST : %s\n", string(temp))

_, _, err := h.authorizer.Authorize(nil)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

delete(data, "spec")
data["status"] = map[string]interface{} {
"allowed": true,
}
output, err := json.MarshalIndent(data, "", " ")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(output)
}

var (
listenAddr string
Expand Down
135 changes: 135 additions & 0 deletions pkg/identity/webhook/handlers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/*
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 webhook

import (
"encoding/json"
"fmt"
"net/http"

"k8s.io/apiserver/pkg/authentication/authenticator"
"k8s.io/apiserver/pkg/authorization/authorizer"
)

type userInfo struct {
Username string `json:"username"`
UID string `json:"uid"`
Groups []string `json:"groups"`
Extra map[string][]string `json:"extra"`
}
type status struct {
Authenticated bool `json:"authenticated"`
User userInfo `json:"user"`
}

type WebhookHandler struct {
Authenticator authenticator.Token
Authorizer authorizer.Authorizer
}

func (h *WebhookHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
var data map[string]interface{}
decoder := json.NewDecoder(r.Body)
defer r.Body.Close()
err := decoder.Decode(&data)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

var apiVersion = data["apiVersion"].(string)
var kind = data["kind"].(string)

if apiVersion != "authentication.k8s.io/v1beta1" && apiVersion != "authorization.k8s.io/v1beta1" {
http.Error(w, fmt.Sprintf("unknown apiVersion %q", apiVersion),
http.StatusBadRequest)
return
}
if kind == "TokenReview" {
var token = data["spec"].(map[string]interface{})["token"].(string)
h.authenticateToken(w, r, token, data)
} else if kind == "SubjectAccessReview" {
h.authorizeToken(w, r, data)
} else {
http.Error(w, fmt.Sprintf("unknown kind/apiVersion %q %q", kind, apiVersion),
http.StatusBadRequest)
}
}

func (h *WebhookHandler) authenticateToken(w http.ResponseWriter, r *http.Request, token string, data map[string]interface{}) {
user, authenticated, err := h.Authenticator.AuthenticateToken(token)

if !authenticated {
var response status
response.Authenticated = false
data["status"] = response

output, err := json.MarshalIndent(data, "", " ")
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusUnauthorized)
w.Write(output)
return
}

var info userInfo
info.Username = user.GetName()
info.UID = user.GetUID()
info.Groups = user.GetGroups()
info.Extra = user.GetExtra()

var response status
response.Authenticated = true
response.User = info

data["status"] = response

output, err := json.MarshalIndent(data, "", " ")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(output)
}

func (h *WebhookHandler) authorizeToken(w http.ResponseWriter, r *http.Request, data map[string]interface{}) {
fmt.Printf("authorizeToken data : %#v\n", data)
temp, _ := json.MarshalIndent(data, "", " ")
fmt.Printf("REQUEST : %s\n", string(temp))

_, _, err := h.Authorizer.Authorize(nil)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

delete(data, "spec")
data["status"] = map[string]interface{} {
"allowed": true,
}
output, err := json.MarshalIndent(data, "", " ")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(output)
}

0 comments on commit 42a3075

Please sign in to comment.