-
Notifications
You must be signed in to change notification settings - Fork 567
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: OS CLI output - merge from branch 'master'
Merge from branch 'master' into 'feat/os-cli-output+test'
- Loading branch information
Showing
145 changed files
with
6,465 additions
and
2,630 deletions.
There are no files selected for viewing
Validating CODEOWNERS rules …
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,68 +1,140 @@ | ||
package httpauth | ||
|
||
import ( | ||
"net/http" | ||
"fmt" | ||
"io" | ||
"log" | ||
"net/url" | ||
|
||
"github.com/dpotapov/go-spnego" | ||
) | ||
|
||
type AuthenticationMechanism int | ||
type AuthenticationMechanism string | ||
type AuthenticationState int | ||
|
||
const maxCycleCount int = 10 | ||
|
||
const ( | ||
NoAuth AuthenticationMechanism = "NoAuth" | ||
Mock AuthenticationMechanism = "Mock" | ||
Negotiate AuthenticationMechanism = "Negotiate" | ||
UnknownMechanism AuthenticationMechanism = "UnknownMechanism" | ||
) | ||
|
||
const ( | ||
NoAuth AuthenticationMechanism = iota | ||
Mock AuthenticationMechanism = iota | ||
Negotiate AuthenticationMechanism = iota | ||
Initial AuthenticationState = iota | ||
Negotiating AuthenticationState = iota | ||
Done AuthenticationState = iota | ||
Error AuthenticationState = iota | ||
Cancel AuthenticationState = iota | ||
Close AuthenticationState = iota | ||
) | ||
|
||
const ( | ||
AuthorizationKey string = "Authorization" | ||
ProxyAuthorizationKey string = "Proxy-Authorization" | ||
ProxyAuthenticateKey string = "Proxy-Authenticate" | ||
) | ||
|
||
type AuthenticationHandlerInterface interface { | ||
Close() | ||
Cancel() | ||
Succesful() | ||
IsStopped() bool | ||
GetAuthorizationValue(url *url.URL, responseToken string) (string, error) | ||
SetLogger(logger *log.Logger) | ||
} | ||
|
||
type AuthenticationHandler struct { | ||
Mechanism AuthenticationMechanism | ||
spnegoProvider SpnegoProvider | ||
Mechanism AuthenticationMechanism | ||
state AuthenticationState | ||
cycleCount int | ||
logger *log.Logger | ||
} | ||
|
||
func (a *AuthenticationHandler) GetAuthorizationValue(url *url.URL) (string, error) { | ||
func NewHandler(mechanism AuthenticationMechanism) AuthenticationHandlerInterface { | ||
a := &AuthenticationHandler{ | ||
spnegoProvider: SpnegoProviderInstance(), | ||
Mechanism: mechanism, | ||
state: Initial, | ||
logger: log.New(io.Discard, "", 0), | ||
} | ||
return a | ||
} | ||
|
||
var authorizeValue string | ||
func (a *AuthenticationHandler) Close() { | ||
a.spnegoProvider.Close() | ||
a.state = Close | ||
} | ||
|
||
tmpRequest := http.Request{ | ||
URL: url, | ||
Header: map[string][]string{}, | ||
} | ||
func (a *AuthenticationHandler) GetAuthorizationValue(url *url.URL, responseToken string) (string, error) { | ||
authorizeValue := "" | ||
mechanism := string(a.Mechanism) | ||
var err error | ||
|
||
if a.Mechanism == Negotiate { // supporting mechanism: Negotiate (SPNEGO) | ||
var provider spnego.Provider = spnego.New() | ||
cannonicalize := false | ||
var token string | ||
var done bool | ||
|
||
if err := provider.SetSPNEGOHeader(&tmpRequest, cannonicalize); err != nil { | ||
if len(responseToken) == 0 && Negotiating == a.state { | ||
a.state = Error | ||
return "", fmt.Errorf("Authentication failed! Unexpected empty token during negotiation!") | ||
} | ||
|
||
a.state = Negotiating | ||
|
||
token, done, err = a.spnegoProvider.GetToken(url, responseToken) | ||
if err != nil { | ||
a.state = Error | ||
return "", err | ||
} | ||
|
||
if done { | ||
a.logger.Println("Security context done!") | ||
} | ||
|
||
authorizeValue = mechanism + " " + token | ||
} else if a.Mechanism == Mock { // supporting mechanism: Mock for testing | ||
tmpRequest.Header.Set(AuthorizationKey, "Mock") | ||
authorizeValue = mechanism + " " + responseToken | ||
a.Succesful() | ||
} | ||
|
||
// ugly work around the fact that go-spnego only adds an "Authorize" Header and not "Proxy-Authorize" | ||
if a.Mechanism != NoAuth { | ||
authorizeValue = tmpRequest.Header.Get(AuthorizationKey) | ||
a.cycleCount++ | ||
if a.cycleCount >= maxCycleCount { | ||
err = fmt.Errorf("Failed to authenticate with %d cycles, stopping now!", maxCycleCount) | ||
} | ||
|
||
return authorizeValue, nil | ||
return authorizeValue, err | ||
} | ||
|
||
func (a *AuthenticationHandler) IsStopped() bool { | ||
return (a.state == Done || a.state == Error || a.state == Cancel || a.state == Close) | ||
} | ||
|
||
func (a *AuthenticationHandler) Reset() { | ||
a.state = Initial | ||
a.cycleCount = 0 | ||
a.logger.Println("AuthenticationHandler.Reset()") | ||
} | ||
|
||
func (a *AuthenticationHandler) Cancel() { | ||
a.state = Cancel | ||
a.logger.Println("AuthenticationHandler.Cancel()") | ||
} | ||
|
||
func (a *AuthenticationHandler) Succesful() { | ||
a.state = Done | ||
a.logger.Println("AuthenticationHandler.Succesful()") | ||
} | ||
|
||
func (a *AuthenticationHandler) SetLogger(logger *log.Logger) { | ||
a.logger = logger | ||
a.spnegoProvider.SetLogger(logger) | ||
} | ||
|
||
func StringFromAuthenticationMechanism(mechanism AuthenticationMechanism) string { | ||
var result string | ||
switch mechanism { | ||
case NoAuth: | ||
result = "NoAuth" | ||
case Negotiate: | ||
result = "Negotiate" | ||
case Mock: | ||
result = "Mock" | ||
default: | ||
result = "Unknonwn AuthenticationMechanism" | ||
} | ||
return result | ||
return string(mechanism) | ||
} | ||
|
||
func AuthenticationMechanismFromString(mechanism string) AuthenticationMechanism { | ||
return AuthenticationMechanism(mechanism) | ||
} |
Oops, something went wrong.