Skip to content

Commit

Permalink
Merge pull request #48 from SUSE/unauthorized_www_authenticate_header
Browse files Browse the repository at this point in the history
HTTP 401 responses should include WWW-Authentciate header
  • Loading branch information
rtamalin authored Aug 5, 2024
2 parents 4731af8 + b79fbb2 commit aa5c44f
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 16 deletions.
19 changes: 19 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,25 @@ func (ar *AppRequest) ContentTypeJSON() {
ar.ContentType("application/json")
}

func (ar *AppRequest) SetWwwAuthenticate(challenge, realm, scope string) {
ar.SetHeader(
"WWW-Authenticate",
fmt.Sprintf(`%s realm="%s" scope="%s"`, challenge, realm, scope),
)
}

func (ar *AppRequest) SetWwwAuthScope(scope string) {
ar.SetWwwAuthenticate("Bearer", "suse-telemetry-service", scope)
}

func (ar *AppRequest) SetWwwAuthReauth() {
ar.SetWwwAuthScope("authenticate")
}

func (ar *AppRequest) SetWwwAuthRegister() {
ar.SetWwwAuthScope("register")
}

func (ar *AppRequest) Status(statusCode int) {
ar.Log.Debug("Response status", slog.Int("code", statusCode))
ar.W.WriteHeader(statusCode)
Expand Down
14 changes: 9 additions & 5 deletions app/handler_authenticate.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ func (a *App) AuthenticateClient(ar *AppRequest) {
return
}
if caReq.ClientId <= 0 {
ar.ErrorResponse(http.StatusBadRequest, "Invalid ClientId value provided")
ar.SetWwwAuthRegister()
ar.ErrorResponse(http.StatusUnauthorized, "Invalid ClientId value provided")
return
}
ar.Log.Debug("Unmarshaled", slog.Any("caReq", &caReq))
Expand All @@ -45,8 +46,8 @@ func (a *App) AuthenticateClient(ar *AppRequest) {

// confirm that the client has been registered
if !client.Exists() {
// TODO: Set WWW-Authenticate header appropriately, per
// https://www.rfc-editor.org/rfc/rfc9110.html#name-www-authenticate
// client needs to register
ar.SetWwwAuthRegister()
ar.ErrorResponse(http.StatusUnauthorized, "Client not registered")
return
}
Expand All @@ -59,12 +60,15 @@ func (a *App) AuthenticateClient(ar *AppRequest) {
slog.String("Req Hash", caReq.InstIdHash.String()),
slog.String("DB Hash", instIdHash.String()),
)
// TODO: Set WWW-Authenticate header appropriately, per
// https://www.rfc-editor.org/rfc/rfc9110.html#name-www-authenticate
// client needs to re-register
ar.SetWwwAuthRegister()
ar.ErrorResponse(http.StatusUnauthorized, "ClientInstanceId mismatch")
return
}

// TODO: return existing token if remaining duration is >= half of
// a new tokens duration

// create a new token for the client
client.AuthToken, err = a.AuthManager.CreateToken()
if err != nil {
Expand Down
39 changes: 28 additions & 11 deletions app/handler_report.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,24 @@ import (
func (a *App) ReportTelemetry(ar *AppRequest) {
ar.Log.Info("Processing")

// verify that a valid authtoken has been provided
// retrieve required headers
hdrClientId := ar.GetClientId()
token := ar.GetAuthToken()

// missing clientId or token suggests client needs to register
if (hdrClientId == "") || (token == "") {
// client needs to register
ar.SetWwwAuthRegister()
ar.ErrorResponse(http.StatusUnauthorized, "Client registration required")
return
}

// verify that a valid authtoken has been provided
if err := a.AuthManager.VerifyToken(token); err != nil {
// TODO: Set WWW-Authenticate header appropriately, per
// https://www.rfc-editor.org/rfc/rfc9110.html#name-www-authenticate
ar.ErrorResponse(http.StatusUnauthorized, "Missing or Invalid Authorization")
// client needs to re-authenticate
ar.SetWwwAuthReauth()
ar.ErrorResponse(http.StatusUnauthorized, "Invalid Authorization")
return
}

ar.Log.Debug(
Expand All @@ -29,12 +41,12 @@ func (a *App) ReportTelemetry(ar *AppRequest) {
)

// verify that the provided client id is a valid number
hdrClientId := ar.GetClientId()
clientId, err := strconv.ParseInt(hdrClientId, 0, 64)
if err != nil {
// TODO: Set WWW-Authenticate header appropriately, per
// https://www.rfc-editor.org/rfc/rfc9110.html#name-www-authenticate
// client needs to register
ar.SetWwwAuthRegister()
ar.ErrorResponse(http.StatusUnauthorized, "Invalid Client Id")
return
}

// verify that the request is from a registered client
Expand All @@ -45,17 +57,22 @@ func (a *App) ReportTelemetry(ar *AppRequest) {
ar.ErrorResponse(http.StatusInternalServerError, "failed to access DB")
return
}

if !client.Exists() {
// TODO: Set WWW-Authenticate header appropriately, per
// https://www.rfc-editor.org/rfc/rfc9110.html#name-www-authenticate
// client needs to register
ar.SetWwwAuthRegister()
ar.ErrorResponse(http.StatusUnauthorized, "Invalid Client Id")
return
}

// verify that the provided authtoken matches last authtoken issued to the client
if client.AuthToken != token {
// TODO: Set WWW-Authenticate header appropriately, per
// https://www.rfc-editor.org/rfc/rfc9110.html#name-www-authenticate
// TODO detect cloned clients, where InstID matches ClientId, but authtoken will
// will be stale
// client needs to re-authenticate
ar.SetWwwAuthReauth()
ar.ErrorResponse(http.StatusUnauthorized, "Invalid Authorization")
return
}

ar.Log.Debug(
Expand Down

0 comments on commit aa5c44f

Please sign in to comment.