|
package server
import (
"context"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"net/http"
"github.com/RedHatInsights/insights-operator-utils/collections"
types "github.com/RedHatInsights/insights-results-types"
"github.com/rs/zerolog/log"
)
const (
|
nosec G101
|
malformedTokenMessage = "Malformed authentication token"
)
|
Identity contains internal user info
|
type Identity = types . Identity
|
Token is x-rh-identity struct
|
type Token = types . Token
|
Authentication middleware for checking auth rights
|
func ( server * HTTPServer ) Authentication ( next http . Handler , noAuthURLs [ ] string ) http . Handler {
return http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
|
for specific URLs it is ok to not use auth. mechanisms at all
this is specific to OpenAPI JSON response and for all OPTION HTTP methods
|
if collections . StringInSlice ( r . RequestURI , noAuthURLs ) || r . Method == "OPTIONS" {
next . ServeHTTP ( w , r )
return
}
token , err := server . getAuthTokenHeader ( w , r )
if err != nil {
log . Error ( ) . Err ( err ) . Msg ( err . Error ( ) )
handleServerError ( w , err )
return
}
|
decode auth. token to JSON string
|
decoded , err := base64 . StdEncoding . DecodeString ( token )
|
if token is malformed return HTTP code 403 to client
|
if err != nil {
|
malformed token, returns with HTTP code 403 as usual
|
log . Error ( ) . Err ( err ) . Msg ( malformedTokenMessage )
handleServerError ( w , & UnauthorizedError { ErrString : malformedTokenMessage } )
return
}
tk := & types . Token { }
if server . Config . AuthType == "xrh" {
|
auth type is xrh (x-rh-identity header)
|
err = json . Unmarshal ( decoded , tk )
if err != nil {
|
malformed token, returns with HTTP code 403 as usual
|
log . Error ( ) . Err ( err ) . Msg ( malformedTokenMessage )
handleServerError ( w , & UnauthorizedError { ErrString : malformedTokenMessage } )
return
}
} else {
err := errors . New ( "unknown auth type" )
log . Error ( ) . Err ( err ) . Send ( )
handleServerError ( w , err )
return
}
if tk . Identity . OrgID == 0 {
msg := fmt . Sprintf ( "error retrieving requester org_id from token. account_number [%v], user data [%+v]" ,
tk . Identity . AccountNumber ,
tk . Identity . User ,
)
log . Error ( ) . Msg ( msg )
handleServerError ( w , & UnauthorizedError { ErrString : msg } )
return
}
if tk . Identity . User . UserID == "" {
tk . Identity . User . UserID = "0"
}
|
Everything went well, proceed with the request and set the
caller to the user retrieved from the parsed token
|
ctx := context . WithValue ( r . Context ( ) , types . ContextKeyUser , tk . Identity )
r = r . WithContext ( ctx )
next . ServeHTTP ( w , r )
} )
}
|
GetCurrentUserID retrieves current user's id from request
|
func ( server * HTTPServer ) GetCurrentUserID ( request * http . Request ) ( types . UserID , error ) {
i := request . Context ( ) . Value ( types . ContextKeyUser )
if i == nil {
log . Error ( ) . Msg ( "user id was not found in request's context" )
return "" , & UnauthorizedError { ErrString : "user id is not provided" }
}
identity , ok := i . ( Identity )
if ! ok {
return "" , fmt . Errorf ( "contextKeyUser has wrong type" )
}
return identity . User . UserID , nil
}
func ( server * HTTPServer ) getAuthTokenHeader ( _ http . ResponseWriter , r * http . Request ) ( string , error ) {
tokenHeader := r . Header . Get ( "x-rh-identity" )
if tokenHeader == "" {
const message = "Missing auth token"
return "" , & UnauthorizedError { ErrString : message }
}
return tokenHeader , nil
}
|