Skip to content

Commit

Permalink
Add basic auth to metrics endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
PatWie committed Jan 6, 2020
1 parent b961a36 commit 7a9e61d
Show file tree
Hide file tree
Showing 10 changed files with 140 additions and 9 deletions.
3 changes: 3 additions & 0 deletions .infomark-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ server:
host: redis_service
port: 6379
database: 0
prometheus:
user: prometheus_user
password: prometheus_password
rabbit_mq:
host: localhost
port: 5672
Expand Down
2 changes: 1 addition & 1 deletion api/app/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func TestAuth(t *testing.T) {

g.BeforeEach(func() {
tape.BeforeEach()
tape.Router, _ = New(tape.DB, false)
tape.Router, _ = New(tape.DB, EmptyHandler(), false)
stores = NewStores(tape.DB)
_ = stores
})
Expand Down
41 changes: 40 additions & 1 deletion api/app/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
package app

import (
"crypto/subtle"
"errors"
"fmt"
"io"
Expand All @@ -32,6 +33,7 @@ import (
"github.com/go-chi/chi/middleware"
"github.com/go-chi/cors"
"github.com/go-chi/render"
"github.com/infomark-org/infomark/auth"
"github.com/infomark-org/infomark/auth/authenticate"
"github.com/infomark-org/infomark/auth/authorize"
"github.com/infomark-org/infomark/configuration"
Expand Down Expand Up @@ -90,6 +92,34 @@ func LoggingMiddleware(next http.Handler) http.Handler {
})
}

func BasicAuthMiddleware(realm string, credentials map[string]string) func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("WWW-Authenticate", fmt.Sprintf(`Basic realm="%s"`, realm))
username, password, ok := r.BasicAuth()
if !ok {
w.Header().Add("WWW-Authenticate", fmt.Sprintf(`Basic realm="%s"`, realm))
render.Render(w, r, auth.ErrUnauthenticated)
return
}
validPassword, userFound := credentials[username]
if !userFound {
w.Header().Add("WWW-Authenticate", fmt.Sprintf(`Basic realm="%s"`, realm))
render.Render(w, r, auth.ErrUnauthenticated)
return
}

if subtle.ConstantTimeCompare([]byte(password), []byte(validPassword)) == 1 {
next.ServeHTTP(w, r)
return
}

w.Header().Add("WWW-Authenticate", fmt.Sprintf(`Basic realm="%s"`, realm))
render.Render(w, r, auth.ErrUnauthenticated)
})
}
}

// VersionMiddleware writes the current API version to the headers.
func VersionMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
Expand Down Expand Up @@ -129,7 +159,7 @@ func NoCache(next http.Handler) http.Handler {
}

// New configures application resources and routes.
func New(db *sqlx.DB, log bool) (*chi.Mux, error) {
func New(db *sqlx.DB, promhttp http.Handler, log bool) (*chi.Mux, error) {
logger := logrus.StandardLogger()

config := &configuration.Configuration.Server
Expand Down Expand Up @@ -170,6 +200,15 @@ func New(db *sqlx.DB, log bool) (*chi.Mux, error) {
r.Use(render.SetContentType(render.ContentTypeJSON))
r.Use(corsConfig().Handler)

basicAuth := BasicAuthMiddleware("Restricted", map[string]string{
configuration.Configuration.Server.Services.Prometheus.User: configuration.Configuration.Server.Services.Prometheus.Password,
})

r.Group(func(r chi.Router) {
r.Use(basicAuth)
r.Handle("/metrics", promhttp)
})

// r.Use(authenticate.AuthenticateAccessJWT)
r.Route("/api", func(r chi.Router) {

Expand Down
70 changes: 70 additions & 0 deletions api/app/router_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// InfoMark - a platform for managing courses with
// distributing exercise sheets and testing exercise submissions
// Copyright (C) 2019 ComputerGraphics Tuebingen
// 2020-present InfoMark.org
// Authors: Patrick Wieschollek
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

package app

import (
"encoding/base64"
"fmt"
"net/http"
"testing"

"github.com/franela/goblin"
"github.com/infomark-org/infomark/configuration"
otape "github.com/infomark-org/infomark/tape"
)

func TestMetrics(t *testing.T) {

g := goblin.Goblin(t)

tape := NewTape()

g.Describe("Metrics", func() {

g.BeforeEach(func() {
tape.BeforeEach()
})

g.It("Should required credentials", func() {
w := tape.Get("/metrics")
g.Assert(w.Code).Equal(http.StatusUnauthorized)

h := make(map[string]interface{})
r := otape.BuildDataRequest("GET", "/metrics", h)

user := configuration.Configuration.Server.Services.Prometheus.User
password := configuration.Configuration.Server.Services.Prometheus.Password

authorization := fmt.Sprintf("%s:%s", user, password)
authorization = base64.StdEncoding.EncodeToString([]byte(authorization))

r.Header.Set("Authorization", "Basic "+authorization)
w = tape.PlayRequest(r)
g.Assert(w.Code).Equal(http.StatusOK)

})

g.AfterEach(func() {
tape.AfterEach()
})

})

}
8 changes: 7 additions & 1 deletion api/app/tape_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ func (t *Tape) NewJWTRequest(loginID int64, root bool) JWTRequest {
}
}

func EmptyHandler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(""))
})
}

type Tape struct {
otape.Tape
DB *sqlx.DB
Expand Down Expand Up @@ -103,6 +109,6 @@ func (t *Tape) BeforeEach() {
panic(err)
}

t.Router, _ = New(t.DB, false)
t.Router, _ = New(t.DB, EmptyHandler(), false)

}
4 changes: 1 addition & 3 deletions api/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,11 @@ func NewServer(config *configuration.ServerConfigurationSchema) (*Server, error)

migration.UpdateDatabase(db, log)

handler, err := app.New(db, true)
handler, err := app.New(db, promhttp.Handler(), true)
if err != nil {
return nil, err
}

handler.Handle("/metrics", promhttp.Handler())

srv := http.Server{
Addr: config.HTTPAddr(),
Handler: handler,
Expand Down
3 changes: 3 additions & 0 deletions cmd/console/configuration_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ func GenerateExampleConfiguration(domain string, root_path string) *configuratio
config.Server.Services.Postgres.Database = "infomark"
config.Server.Services.Postgres.Password = auth.GenerateToken(32)

config.Server.Services.Prometheus.User = "prometheus_user"
config.Server.Services.Prometheus.Password = auth.GenerateToken(32)

config.Server.Paths.Uploads = root_path + "/uploads"
config.Server.Paths.Common = root_path + "/common"
config.Server.Paths.GeneratedFiles = root_path + "/generated_files"
Expand Down
5 changes: 4 additions & 1 deletion configuration/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,11 @@ type ServerConfigurationSchema struct {
Host string `yaml:"host"`
Port int `yaml:"port"`
Database int `yaml:"database"`
// Connection string `yaml:"connection"`
} `yaml:"redis"`
Prometheus struct {
User string `yaml:"user"`
Password string `yaml:"password"`
} `yaml:"prometheus"`
RabbitMQ RabbitMQConfiguration `yaml:"rabbit_mq"`
Postgres struct {
// Connection string `yaml:"connection"`
Expand Down
3 changes: 3 additions & 0 deletions configuration/example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ server:
host: redis_service
port: 6379
database: 0
prometheus:
user: prometheus_user
password: 3a267976f71fad9fa1f8e8d1ff0ad5032d40c93fc91b5d1201b3ca68376eb2ae
rabbit_mq:
host: rabbitmq_service
port: 5672
Expand Down
10 changes: 8 additions & 2 deletions docs/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,15 @@ type Routes struct {
Path string
}

func EmptyHandler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(""))
})
}

func GetAllRoutes() []*Routes {
db, _ := sqlx.Open("sqlite3", ":memory:")
r, _ := app.New(db, false)
r, _ := app.New(db, EmptyHandler(), false)

routes := []*Routes{}

Expand Down Expand Up @@ -127,7 +133,7 @@ func main() {
f.WriteString(fmt.Sprintf(" email: Patrick.Wieschollek@uni-tuebingen.de\n"))
f.WriteString(fmt.Sprintf(" url: https://uni-tuebingen.de\n"))
f.WriteString(fmt.Sprintf("servers:\n"))
f.WriteString(fmt.Sprintf(" - url: http://localhost:3000/api/v1\n"))
f.WriteString(fmt.Sprintf(" - url: http://localhost:2020/api/v1\n"))
f.WriteString(fmt.Sprintf("security:\n"))
f.WriteString(fmt.Sprintf(" - bearerAuth: []\n"))
f.WriteString(fmt.Sprintf(" - cookieAuth: []\n"))
Expand Down

0 comments on commit 7a9e61d

Please sign in to comment.