forked from aarondl/authboss
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrouter.go
More file actions
executable file
·161 lines (139 loc) · 4.73 KB
/
router.go
File metadata and controls
executable file
·161 lines (139 loc) · 4.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
package authboss
import (
"fmt"
"io"
"net/http"
"path"
"strings"
)
// HandlerFunc augments http.HandlerFunc with a context and error handling.
type HandlerFunc func(*Context, http.ResponseWriter, *http.Request) error
// RouteTable is a routing table from a path to a handlerfunc.
type RouteTable map[string]HandlerFunc
// NewRouter returns a router to be mounted at some mountpoint.
func (a *Authboss) NewRouter() http.Handler {
if a.mux != nil {
return a.mux
}
a.mux = http.NewServeMux()
for name, mod := range a.loadedModules {
for route, handler := range mod.Routes() {
fmt.Fprintf(a.LogWriter, "%-10s Route: %s\n", "["+name+"]", path.Join(a.MountPath, route))
a.mux.Handle(path.Join(a.MountPath, route), contextRoute{a, handler})
}
}
a.mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if a.NotFoundHandler != nil {
a.NotFoundHandler.ServeHTTP(w, r)
} else {
w.WriteHeader(http.StatusNotFound)
io.WriteString(w, "404 Page not found")
}
})
return a.mux
}
type contextRoute struct {
*Authboss
fn HandlerFunc
}
func (c contextRoute) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Instantiate the context
fmt.Println("We are routing ServeHTTP ", r.URL.Path)
ctx := c.Authboss.InitContext(w, r)
temp := strings.Split(r.Proto, "/")
protocal := "http"
if len(temp) > 1 {
protocal = strings.ToLower(temp[0])
}
c.Authboss.RootURL = protocal + "://" + r.Host
// Check to make sure we actually need to visit this route
if strings.Contains(r.URL.Path, "/auth/recover/complete") {
fmt.Println(" we requestetd reset password, so we are logging out logged in user ")
ctx.SessionStorer.Del(SessionKey)
ctx.CookieStorer.Del(CookieRemember)
ctx.SessionStorer.Del(SessionLastAction)
}
if redirectIfLoggedIn(ctx, w, r) {
return
}
// Call the handler
err := c.fn(ctx, w, r)
fmt.Fprintf(c.LogWriter, "Error Occurred at %s: %v", r.URL.Path, err)
if err == nil {
return
}
// Log the error
// Do specific error handling for special kinds of errors.
// io.WriteString(w, fmt.Sprintf("We got error - %+v", err))
w.Write([]byte(fmt.Sprintf("We got error - %+v", err)))
switch e := err.(type) {
case ErrAndRedirect:
if len(e.FlashSuccess) > 0 {
ctx.SessionStorer.Put(FlashSuccessKey, e.FlashSuccess)
}
if len(e.FlashError) > 0 {
ctx.SessionStorer.Put(FlashErrorKey, e.FlashError)
}
http.Redirect(w, r, e.Location, http.StatusFound)
case ClientDataErr:
if c.BadRequestHandler != nil {
c.BadRequestHandler.ServeHTTP(w, r)
} else {
w.WriteHeader(http.StatusBadRequest)
io.WriteString(w, fmt.Sprintf("We got error - %+v", err))
}
default:
if c.ErrorHandler != nil {
c.ErrorHandler.ServeHTTP(w, r)
} else {
w.WriteHeader(http.StatusForbidden)
io.WriteString(w, err.Error())
}
}
}
// redirectIfLoggedIn checks a user's existence by using currentUser. This is done instead of
// a simple Session cookie check so that the remember module has a chance to log the user in
// before they are determined to "not be logged in".
//
// The exceptional routes are sort of hardcoded in a terrible way in here, later on this could move to some
// configuration or something more interesting.
func redirectIfLoggedIn(ctx *Context, w http.ResponseWriter, r *http.Request) (handled bool) {
// If it's a log out url, always let it pass through.
if strings.HasSuffix(r.URL.Path, "/logout") {
return false
}
// If it's an auth url, allow them through if they're half-authed.
if strings.HasSuffix(r.URL.Path, "/auth") || strings.Contains(r.URL.Path, "/oauth2/") {
if halfAuthed, ok := ctx.SessionStorer.Get(SessionHalfAuthKey); ok && halfAuthed == "true" {
return false
}
}
// Otherwise, check if they're logged in, this uses hooks to allow remember
// to set the session cookie
cu, err := ctx.currentUser(ctx, w, r)
// if the user was not found, that means the user was deleted from the underlying
// storer and we should just remove this session cookie and allow them through.
// if it's a generic error, 500
// if the user is found, redirect them away from this page, because they don't need
// to see it.
if err == ErrUserNotFound {
uname, _ := ctx.SessionStorer.Get(SessionKey)
fmt.Fprintf(ctx.LogWriter, "user (%s) has session cookie but user not found, removing cookie", uname)
ctx.SessionStorer.Del(SessionKey)
return false
} else if err != nil {
// fmt.Fprintf(ctx.LogWriter, "error occurred reading current user at %s: %v", r.URL.Path, err)
// w.WriteHeader(http.StatusForbidden)
// io.WriteString(w, err.Error())
return false
}
if cu != nil {
if redir := r.FormValue(FormValueRedirect); len(redir) > 0 {
http.Redirect(w, r, redir, http.StatusFound)
} else {
http.Redirect(w, r, ctx.AuthLoginOKPath, http.StatusFound)
}
return true
}
return false
}