aws api auth plugins
Showing
1 changed file
with
154 additions
and
0 deletions
plugins/apiauth/apiauth.go
0 → 100644
| 1 | // Copyright 2014 beego Author. All Rights Reserved. | ||
| 2 | // | ||
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 4 | // you may not use this file except in compliance with the License. | ||
| 5 | // You may obtain a copy of the License at | ||
| 6 | // | ||
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
| 8 | // | ||
| 9 | // Unless required by applicable law or agreed to in writing, software | ||
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 12 | // See the License for the specific language governing permissions and | ||
| 13 | // limitations under the License. | ||
| 14 | |||
| 15 | // Package apiauth provides handlers to enable apiauth support. | ||
| 16 | // Simple Usage: | ||
| 17 | // import( | ||
| 18 | // "github.com/astaxie/beego" | ||
| 19 | // "github.com/astaxie/beego/plugins/apiauth" | ||
| 20 | // ) | ||
| 21 | // | ||
| 22 | // func main(){ | ||
| 23 | // // apiauth every request | ||
| 24 | // beego.InsertFilter("*", beego.BeforeRouter,auth.APIAuth("appid","appkey")) | ||
| 25 | // beego.Run() | ||
| 26 | // } | ||
| 27 | // | ||
| 28 | package apiauth | ||
| 29 | |||
| 30 | import ( | ||
| 31 | "crypto/hmac" | ||
| 32 | "crypto/sha256" | ||
| 33 | "encoding/base64" | ||
| 34 | "fmt" | ||
| 35 | "net/url" | ||
| 36 | "sort" | ||
| 37 | "strings" | ||
| 38 | "time" | ||
| 39 | |||
| 40 | "github.com/astaxie/beego" | ||
| 41 | "github.com/astaxie/beego/context" | ||
| 42 | ) | ||
| 43 | |||
| 44 | type AppIdToAppSecret func(string) string | ||
| 45 | |||
| 46 | func APIBaiscAuth(appid, appkey string) beego.FilterFunc { | ||
| 47 | ft := func(aid string) string { | ||
| 48 | if aid == appid { | ||
| 49 | return appkey | ||
| 50 | } | ||
| 51 | return "" | ||
| 52 | } | ||
| 53 | return APIAuthWithFunc(ft, 300) | ||
| 54 | } | ||
| 55 | |||
| 56 | func APIAuthWithFunc(f AppIdToAppSecret, timeout int) beego.FilterFunc { | ||
| 57 | return func(ctx *context.Context) { | ||
| 58 | if ctx.Input.Query("appid") == "" { | ||
| 59 | ctx.Output.SetStatus(403) | ||
| 60 | ctx.WriteString("miss query param: appid") | ||
| 61 | return | ||
| 62 | } | ||
| 63 | appsecret := f(ctx.Input.Query("appid")) | ||
| 64 | if appsecret == "" { | ||
| 65 | ctx.Output.SetStatus(403) | ||
| 66 | ctx.WriteString("not exist this appid") | ||
| 67 | return | ||
| 68 | } | ||
| 69 | if ctx.Input.Query("signature") == "" { | ||
| 70 | ctx.Output.SetStatus(403) | ||
| 71 | ctx.WriteString("miss query param: signature") | ||
| 72 | return | ||
| 73 | } | ||
| 74 | if ctx.Input.Query("timestamp") == "" { | ||
| 75 | ctx.Output.SetStatus(403) | ||
| 76 | ctx.WriteString("miss query param: timestamp") | ||
| 77 | return | ||
| 78 | } | ||
| 79 | u, err := time.Parse("2006-01-02 15:04:05", ctx.Input.Query("timestamp")) | ||
| 80 | if err != nil { | ||
| 81 | ctx.Output.SetStatus(403) | ||
| 82 | ctx.WriteString("timestamp format is error, should 2006-01-02 15:04:05") | ||
| 83 | return | ||
| 84 | } | ||
| 85 | t := time.Now() | ||
| 86 | if (t.Second() - u.Second()) > timeout { | ||
| 87 | ctx.Output.SetStatus(403) | ||
| 88 | ctx.WriteString("timeout! the request time is long ago, please try again") | ||
| 89 | return | ||
| 90 | } | ||
| 91 | if ctx.Input.Query("signature") != | ||
| 92 | Signature(appsecret, ctx.Input.Method(), ctx.Request.Form, ctx.Input.Uri()) { | ||
| 93 | ctx.Output.SetStatus(403) | ||
| 94 | ctx.WriteString("auth failed") | ||
| 95 | } | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | func Signature(appsecret, method string, params url.Values, RequestURI string) (result string) { | ||
| 100 | var query string | ||
| 101 | pa := make(map[string]string) | ||
| 102 | for k, v := range params { | ||
| 103 | pa[k] = v[0] | ||
| 104 | } | ||
| 105 | vs := mapSorter(pa) | ||
| 106 | vs.Sort() | ||
| 107 | for i := 0; i < vs.Len(); i++ { | ||
| 108 | if vs.Keys[i] == "signature" { | ||
| 109 | continue | ||
| 110 | } | ||
| 111 | if vs.Keys[i] != "" && vs.Vals[i] != "" { | ||
| 112 | query = fmt.Sprintf("%v%v%v", query, vs.Keys[i], vs.Vals[i]) | ||
| 113 | } | ||
| 114 | } | ||
| 115 | string_to_sign := fmt.Sprintf("%v\n%v\n%v\n", method, query, RequestURI) | ||
| 116 | |||
| 117 | sha256 := sha256.New | ||
| 118 | hash := hmac.New(sha256, []byte(appsecret)) | ||
| 119 | hash.Write([]byte(string_to_sign)) | ||
| 120 | sha := base64.StdEncoding.EncodeToString(hash.Sum(nil)) | ||
| 121 | sha = url.QueryEscape(sha) | ||
| 122 | sha = strings.Replace(sha, "+", "%20", -1) | ||
| 123 | sha = strings.Replace(sha, "*", "%2A", -1) | ||
| 124 | sha = strings.Replace(sha, "%7E", "~", -1) | ||
| 125 | return sha | ||
| 126 | } | ||
| 127 | |||
| 128 | type valSorter struct { | ||
| 129 | Keys []string | ||
| 130 | Vals []string | ||
| 131 | } | ||
| 132 | |||
| 133 | func mapSorter(m map[string]string) *valSorter { | ||
| 134 | vs := &valSorter{ | ||
| 135 | Keys: make([]string, 0, len(m)), | ||
| 136 | Vals: make([]string, 0, len(m)), | ||
| 137 | } | ||
| 138 | for k, v := range m { | ||
| 139 | vs.Keys = append(vs.Keys, k) | ||
| 140 | vs.Vals = append(vs.Vals, v) | ||
| 141 | } | ||
| 142 | return vs | ||
| 143 | } | ||
| 144 | |||
| 145 | func (vs *valSorter) Sort() { | ||
| 146 | sort.Sort(vs) | ||
| 147 | } | ||
| 148 | |||
| 149 | func (vs *valSorter) Len() int { return len(vs.Keys) } | ||
| 150 | func (vs *valSorter) Less(i, j int) bool { return vs.Keys[i] < vs.Keys[j] } | ||
| 151 | func (vs *valSorter) Swap(i, j int) { | ||
| 152 | vs.Vals[i], vs.Vals[j] = vs.Vals[j], vs.Vals[i] | ||
| 153 | vs.Keys[i], vs.Keys[j] = vs.Keys[j], vs.Keys[i] | ||
| 154 | } |
-
Please register or sign in to post a comment