5a087b28 by astaxie

aws api auth plugins

1 parent 9b402718
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 }
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!