|
|
Package auth contains implementation of authentication mechanism used to
validate user credentials and create auth token.
Generated documentation is available at:
https://godoc.org/github.com/RedHatInsights/insights-operator-ldapauth/auth
Documentation in literate-programming-style is available at:
https://redhatinsights.github.io/insights-operator-ldapauth/packages/auth/auth.html
|
package auth
import (
"crypto/tls"
"errors"
"fmt"
"log"
"os"
"strings"
"github.com/RedHatInsights/insights-operator-utils/responses"
"github.com/dgrijalva/jwt-go"
"gopkg.in/ldap.v3"
)
|
NoAccessMessage - Error message for user with no access
|
const NoAccessMessage = "User has no rights to access"
|
Token JWT claims struct
|
type Token struct {
Login string
jwt . StandardClaims
}
|
Account a struct to rep user account
|
type Account struct {
Login string `json:"login"`
Password string `json:"password"`
Token string `json:"token"`
}
|
GetTokenPasswordFromEnv tries to read token password from the environment
variable. Content of the variable (string) is converted into array of bytes
to be usable.
|
func GetTokenPasswordFromEnv ( ) [ ] byte {
return [ ] byte ( os . Getenv ( "token_password" ) )
}
func createLdapConnection ( ldapHost string ) ( * ldap . Conn , error ) {
var err error
conn , err := ldap . Dial ( "tcp" , fmt . Sprintf ( "%s:%d" , ldapHost , 389 ) )
if err != nil {
return nil , err
}
return conn , nil
}
func ldapAuth ( login , password string , client ldap . Client ) ( bool , error ) {
var err error
|
Reconnect with TLS
disable "G402 (CWE-295): TLS InsecureSkipVerify set true."
nosec G402
|
err = client . StartTLS ( & tls . Config { InsecureSkipVerify : true } )
if err != nil {
return false , err
}
defer client . Close ( )
|
// Search for the given username
|
searchRequest := ldap . NewSearchRequest (
"dc=redhat,dc=com" ,
ldap . ScopeWholeSubtree , ldap . NeverDerefAliases , 0 , 0 , false ,
fmt . Sprintf ( "(&(uid=%s))" , login ) ,
[ ] string { "dn" , "memberOf" } ,
nil ,
)
sr , err := client . Search ( searchRequest )
if err != nil {
return false , err
}
if len ( sr . Entries ) != 1 {
return false , errors . New ( "User does not exist or too many entries returned" )
}
isInGroup := false
for i := 0 ; i < len ( sr . Entries [ 0 ] . Attributes [ 0 ] . Values ) ; i ++ {
entries := strings . Split ( sr . Entries [ 0 ] . Attributes [ 0 ] . Values [ i ] , "," )
if entries [ 0 ] == "cn=ccx-dev" {
isInGroup = true
break
}
}
if ! isInGroup {
return false , errors . New ( NoAccessMessage )
}
|
Bind as the user to verify their password
|
err = client . Bind ( sr . Entries [ 0 ] . DN , password )
if err != nil {
return false , err
}
return true , nil
}
|
Authenticate - validate user credentials and create auth token
|
func Authenticate ( login , password , ldapHost string ) ( map [ string ] interface { } , error ) {
var err error
account := & Account { }
account . Login = login
conn , err := createLdapConnection ( ldapHost )
if err != nil {
log . Println ( err )
r := responses . BuildResponse ( err . Error ( ) )
return r , err
}
ok , err := ldapAuth ( login , password , conn )
|
attempt the authentication
|
if err != nil || ! ok {
log . Println ( err )
r := responses . BuildResponse ( err . Error ( ) )
return r , err
}
|
Create JWT token
|
tk := & Token { Login : account . Login }
token := jwt . NewWithClaims ( jwt . GetSigningMethod ( "HS256" ) , tk )
tokenString , _ := token . SignedString ( GetTokenPasswordFromEnv ( ) )
|
Store the token in the response
|
account . Token = tokenString
resp := responses . BuildResponse ( "ok" )
resp [ "account" ] = account
return resp , nil
}
|