|
package server
|
Documentation in literate-programming-style is available at:
https://redhatinsights.github.io/insights-operator-ldapauth/packages/server/auth.html
|
import (
"context"
"encoding/json"
"github.com/RedHatInsights/insights-operator-utils/responses"
jwt "github.com/dgrijalva/jwt-go"
auth "github.com/redhatinsights/insights-operator-ldapauth/auth"
"log"
"net/http"
"strings"
)
type contextKey string
const (
contextKeyUser = contextKey ( "user" )
)
|
Login handler for login route
|
func ( s * Server ) Login ( writer http . ResponseWriter , request * http . Request ) {
account := & auth . Account { }
|
decode the request body into struct and failed if any error occur
|
err := json . NewDecoder ( request . Body ) . Decode ( account )
if err != nil {
err := responses . SendBadRequest ( writer , "Invalid request" )
if err != nil {
log . Println ( err )
}
return
}
resp , err := auth . Authenticate ( account . Login , account . Password , s . LDAP )
if err != nil {
err := responses . Send ( http . StatusUnauthorized , writer , resp )
if err != nil {
log . Println ( err )
}
return
}
err = responses . SendOK ( writer , resp )
if err != nil {
log . Println ( err )
}
}
|
JWTAuthentication - middleware for authenticate user by Token
|
func ( s * Server ) JWTAuthentication ( next http . Handler ) http . Handler {
return http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
|
List of endpoints that doesn't require auth
|
notAuth := [ ] string { APIPrefix + "login" }
|
current request path
|
requestPath := r . URL . Path
|
check if request does not need authentication, serve the request if it doesn't need it
|
for _ , value := range notAuth {
if value == requestPath {
next . ServeHTTP ( w , r )
return
}
}
|
grab the token from the header
|
tokenHeader := r . Header . Get ( "Authorization" )
if tokenHeader == "" {
|
Token is missing, return with HTTP error code 403 Unauthorized
|
err := responses . SendForbidden ( w , "Missing auth token" )
if err != nil {
log . Println ( err )
}
return
}
|
the token normally comes in format Bearer {token-body} , we
check if the retrieved token matched this requirement
|
splitted := strings . Split ( tokenHeader , " " )
if len ( splitted ) != 2 {
err := responses . SendForbidden ( w , "Invalid/Malformed auth token" )
if err != nil {
log . Println ( err )
}
return
}
|
grab the token part, what we are truly interested in
|
tokenPart := splitted [ 1 ]
tk := & auth . Token { }
token , err := jwt . ParseWithClaims ( tokenPart , tk , func ( token * jwt . Token ) ( interface { } , error ) {
return auth . GetTokenPasswordFromEnv ( ) , nil
} )
if err != nil {
|
malformed token detected, returns with HTTP code 403 as usual
|
err := responses . SendForbidden ( w , "Malformed authentication token" )
if err != nil {
log . Println ( err )
}
return
}
if ! token . Valid {
|
token is invalid, maybe not signed on this server
|
err := responses . SendForbidden ( w , "Token is not valid." )
if err != nil {
log . Println ( err )
}
return
}
|
everything went well, proceed with the request and set the
caller to the user retrieved from the parsed token
|
ctx := context . WithValue ( r . Context ( ) , contextKeyUser , tk . Login )
r = r . WithContext ( ctx )
|
Proceed to proxy
|
next . ServeHTTP ( w , r )
} )
}
|