diff --git a/.gitignore b/.gitignore index e69de29..45e4f4b 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1,33 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib +*.swp + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +vendor/ +bin/ + +.idea/ +*.iml +.vscode/ + +tmp/ +tmpFiles/ +*.tmp +logs/ +files/ +lastupdate.tmp +commentsRouter*.go + +# ignore build result +casdoor +server diff --git a/internal/config/config.go b/internal/config/config.go index 86d47f0..e10cf68 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -1,4 +1,4 @@ -// Copyright 2021 The casbin Authors. All Rights Reserved. +// Copyright 2021 The Casdoor Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -11,15 +11,16 @@ // 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 config import ( + _ "embed" "encoding/json" "io/ioutil" "log" "github.com/casdoor/casdoor-go-sdk/auth" - _ "embed" ) //go:embed token.pem @@ -46,10 +47,13 @@ func LoadConfigFile(path string) { if err != nil { log.Fatalf("failed to unmarshal config file %s: %s", path, err.Error()) } - auth.InitConfig(CurrentConfig.CasdoorEndpoint, + + auth.InitConfig( + CurrentConfig.CasdoorEndpoint, CurrentConfig.CasdoorClientId, CurrentConfig.CasdoorClientSecret, CasdoorJwtSecret, CurrentConfig.CasdoorOrganization, - CurrentConfig.CasdoorApplication) + CurrentConfig.CasdoorApplication, + ) } diff --git a/internal/handler/casdoor_handler.go b/internal/handler/casdoor_handler.go index 2c2dbcf..93604b4 100644 --- a/internal/handler/casdoor_handler.go +++ b/internal/handler/casdoor_handler.go @@ -1,4 +1,4 @@ -// Copyright 2021 The casbin Authors. All Rights Reserved. +// Copyright 2021 The Casdoor Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -11,6 +11,7 @@ // 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 handler import ( @@ -29,6 +30,15 @@ import ( "github.com/gin-gonic/gin" ) +type Replacement struct { + ShouldReplaceBody bool `json:"shouldReplaceBody"` + Body string `json:"body"` + // ShouldReplaceUri bool `json:"shouldReplaceUri"` + // Uri string `json:"uri"` + ShouldReplaceHeader bool `json:"shouldReplaceHeader"` + Header map[string][]string `json:"Header"` +} + func ForwardAuthHandler(c *gin.Context) { // fmt.Println(c.Request.Host) // fmt.Println(body) @@ -64,7 +74,7 @@ func ForwardAuthHandlerWithoutState(c *gin.Context) { c.JSON(http.StatusInternalServerError, err.Error()) return } - callbackURL:=strings.TrimRight(config.CurrentConfig.PluginEndpoint,"/")+"/callback" + callbackURL := strings.TrimRight(config.CurrentConfig.PluginEndpoint, "/") + "/callback" //generate redirect url redirectURL := fmt.Sprintf("%s/login/oauth/authorize?client_id=%s&response_type=code&redirect_uri=%s&scope=read&state=%s", config.CurrentConfig.CasdoorEndpoint, config.CurrentConfig.CasdoorClientId, @@ -98,14 +108,14 @@ func CasdoorCallbackHandler(c *gin.Context) { stateString := c.Query("state") code := c.Query("code") //write into cookie - var splits=strings.Split(config.CurrentConfig.PluginEndpoint,"://") - if len(splits)<2{ + var splits = strings.Split(config.CurrentConfig.PluginEndpoint, "://") + if len(splits) < 2 { c.JSON(500, gin.H{ "error": "invalid webhook address in configuration" + stateString, }) return } - domain:=splits[1] + domain := splits[1] c.SetCookie("client-code", code, 3600, "/", domain, false, true) c.SetCookie("client-state", stateString, 3600, "/", domain, false, true) stateNonce, _ := strconv.Atoi(stateString) diff --git a/internal/handler/init.go b/internal/handler/init.go index f3240f4..8ed0cf1 100644 --- a/internal/handler/init.go +++ b/internal/handler/init.go @@ -1,4 +1,4 @@ -// Copyright 2021 The casbin Authors. All Rights Reserved. +// Copyright 2021 The Casdoor Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -11,18 +11,24 @@ // 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 handler import "traefikcasdoor/internal/httpstate" -import "log" -var stateStorage httpstate.StateStorage +var stateStorage StateStorage + +type StateStorage interface { + SetState(state *httpstate.State) (int, error) + PopState(nonce int) (*httpstate.State, error) + GetState(nonce int) (*httpstate.State, error) +} func init() { storage, err := httpstate.NewStateMemoryStorage() if err != nil { - log.Printf("error happened when creating StateMemoryStorage\n") - return + panic("error happened when creating StateMemoryStorage") } + stateStorage = storage } diff --git a/internal/handler/replacement.go b/internal/handler/replacement.go deleted file mode 100644 index c114d67..0000000 --- a/internal/handler/replacement.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2021 The casbin Authors. All Rights Reserved. -// -// 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 handler - -type Replacement struct { - ShouldReplaceBody bool `json:"shouldReplaceBody"` - Body string `json:"body"` - // ShouldReplaceUri bool `json:"shouldReplaceUri"` - // Uri string `json:"uri"` - ShouldReplaceHeader bool `json:"shouldReplaceHeader"` - Header map[string][]string `json:"Header"` -} diff --git a/internal/handler/util_handler.go b/internal/handler/util_handler.go index a7bae37..5e065cc 100644 --- a/internal/handler/util_handler.go +++ b/internal/handler/util_handler.go @@ -1,4 +1,4 @@ -// Copyright 2021 The casbin Authors. All Rights Reserved. +// Copyright 2021 The Casdoor Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -11,6 +11,7 @@ // 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 handler import ( diff --git a/internal/httpstate/state.go b/internal/httpstate/state.go index 4e5d6c2..6ead70a 100644 --- a/internal/httpstate/state.go +++ b/internal/httpstate/state.go @@ -1,4 +1,4 @@ -// Copyright 2021 The casbin Authors. All Rights Reserved. +// Copyright 2021 The Casdoor Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -11,6 +11,7 @@ // 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 httpstate import "net/http" diff --git a/internal/httpstate/state_memory_storage.go b/internal/httpstate/state_memory_storage.go index 1330bca..fb8a9eb 100644 --- a/internal/httpstate/state_memory_storage.go +++ b/internal/httpstate/state_memory_storage.go @@ -1,4 +1,4 @@ -// Copyright 2021 The casbin Authors. All Rights Reserved. +// Copyright 2021 The Casdoor Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -11,6 +11,7 @@ // 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 httpstate import ( @@ -46,6 +47,7 @@ func (s *StateMemoryStorage) PopState(nonce int) (*State, error) { if !ok { return nil, fmt.Errorf("state %d not found", nonce) } + delete(s.content, nonce) return state, nil @@ -57,6 +59,7 @@ func (s *StateMemoryStorage) GetState(nonce int) (*State, error) { if !ok { return nil, fmt.Errorf("state %d not found", nonce) } + return state, nil } diff --git a/internal/httpstate/state_storage.go b/internal/httpstate/state_storage.go deleted file mode 100644 index 8073e65..0000000 --- a/internal/httpstate/state_storage.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2021 The casbin Authors. All Rights Reserved. -// -// 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 httpstate - -type StateStorage interface { - SetState(state *State) (int, error) - PopState(nonce int) (*State, error) - GetState(nonce int) (*State, error) -} diff --git a/plugins-local/src/github.com/casdoor/plugindemo/plugin.go b/plugins-local/src/github.com/casdoor/plugindemo/plugin.go index b052a2b..69de5b9 100644 --- a/plugins-local/src/github.com/casdoor/plugindemo/plugin.go +++ b/plugins-local/src/github.com/casdoor/plugindemo/plugin.go @@ -1,4 +1,4 @@ -// Copyright 2021 The casbin Authors. All Rights Reserved. +// Copyright 2021 The Casdoor Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -11,6 +11,7 @@ // 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 plugindemo import ( @@ -20,7 +21,6 @@ import ( "fmt" "io/ioutil" "net/http" - "time" ) @@ -51,8 +51,10 @@ type Plugin struct { webhook string } -/* New created a new Demo plugin. -This plugin do the following acitions successively +/* + New created a new Demo plugin. + +# This plugin do the following acitions successively 1. forward the request to the casbin auth webhook to ask for the opinion. 2. if the status code is 2xx,this plugin will modify the original request according to the response(which is actually a json-marshaled Replacement struct). Otherwise, the body as long as the status code will be directly send back(to client), without sending original request to following handlers. @@ -70,8 +72,9 @@ func (p *Plugin) ServeHTTP(rw http.ResponseWriter, req *http.Request) { p.next.ServeHTTP(rw, req) //webhook is disabled, let it pass return } + client := &http.Client{Timeout: 5 * time.Second} - client.CheckRedirect=func(req *http.Request, via []*http.Request) error {return http.ErrUseLastResponse} + client.CheckRedirect = func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse } //forward this to the specified webhook reqForWebhook, err := p.copyRequestForWebhook(req) if err != nil { @@ -92,7 +95,7 @@ func (p *Plugin) ServeHTTP(rw http.ResponseWriter, req *http.Request) { //but, the body, the header, the uri(not url) may be replaced //if the response want we to do so. // if the status code is not what we want, the response will be directly returned to user - + if resp.StatusCode >= 200 && resp.StatusCode < 300 { //pass, replace the header if necessary responseBody, err := ioutil.ReadAll(resp.Body) @@ -146,7 +149,6 @@ The request method,and the body and the header sent into the plugin will be copi (because when a request enters plugin of traefik, the original information like uri and url will be put into header, so replicating the header will be enough for webhook to get all information.) Considering that the Body field in http.Request is a read closer, thus unavailable for subsequent procedures to read. Therefore, the Body will be restored by ioutil.NopCloser - */ func (p *Plugin) copyRequestForWebhook(req *http.Request) (*http.Request, error) { requestBody, err := ioutil.ReadAll(req.Body) @@ -165,7 +167,7 @@ func (p *Plugin) copyRequestForWebhook(req *http.Request) (*http.Request, error) //copy the header reqForWebhook.Header = req.Header.Clone() //add uri if there is - reqForWebhook.Header.Set("X-Forwarded-URI",req.RequestURI) + reqForWebhook.Header.Set("X-Forwarded-URI", req.RequestURI) //and the cookie for casbin-plugin // cookie,err:=req.Cookie("Casbin-Plugin-ClientCode") @@ -211,8 +213,8 @@ func (p *Plugin) modifyRequestForTraefik(req *http.Request, replacement Replacem req.AddCookie(cookie) } - newRequest.RemoteAddr=req.RemoteAddr - newRequest.RequestURI=req.RequestURI + newRequest.RemoteAddr = req.RemoteAddr + newRequest.RequestURI = req.RequestURI return newRequest, nil diff --git a/plugins-local/src/github.com/casdoor/plugindemo/plugin_test.go b/plugins-local/src/github.com/casdoor/plugindemo/plugin_test.go index e212afb..499c710 100644 --- a/plugins-local/src/github.com/casdoor/plugindemo/plugin_test.go +++ b/plugins-local/src/github.com/casdoor/plugindemo/plugin_test.go @@ -1,4 +1,4 @@ -// Copyright 2021 The casbin Authors. All Rights Reserved. +// Copyright 2021 The Casdoor Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -11,6 +11,7 @@ // 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 plugindemo import ( @@ -43,7 +44,7 @@ func TestCopyRequestForWebhook(t *testing.T) { So(err, ShouldBeNil) So(string(body), ShouldEqual, "testbody") So(newRequest.URL.Host, ShouldEqual, "webhook.com") - delete(newRequest.Header,"X-Forwarded-Uri") + delete(newRequest.Header, "X-Forwarded-Uri") So(newRequest.Header, ShouldResemble, request.Header) cookie2, err := newRequest.Cookie("Casbin-Plugin-ClientCode") So(err, ShouldBeNil)