diff --git a/pkg/api/login.go b/pkg/api/login.go index 511b0007ced..9ebaf1e19ea 100644 --- a/pkg/api/login.go +++ b/pkg/api/login.go @@ -11,6 +11,7 @@ import ( "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/metrics" + "github.com/grafana/grafana/pkg/infra/network" "github.com/grafana/grafana/pkg/login" "github.com/grafana/grafana/pkg/middleware" "github.com/grafana/grafana/pkg/models" @@ -248,7 +249,15 @@ func (hs *HTTPServer) loginUserWithUser(user *models.User, c *models.ReqContext) return errors.New("could not login user") } - userToken, err := hs.AuthTokenService.CreateToken(c.Req.Context(), user.Id, c.RemoteAddr(), c.Req.UserAgent()) + addr := c.RemoteAddr() + ip, err := network.GetIPFromAddress(addr) + if err != nil { + hs.log.Debug("Failed to get IP from client address", "addr", addr) + ip = nil + } + + hs.log.Debug("Got IP address from client address", "addr", addr, "ip", ip) + userToken, err := hs.AuthTokenService.CreateToken(c.Req.Context(), user.Id, ip, c.Req.UserAgent()) if err != nil { return errutil.Wrap("failed to create auth token", err) } diff --git a/pkg/api/login_test.go b/pkg/api/login_test.go index 0c584622a59..5abede806d3 100644 --- a/pkg/api/login_test.go +++ b/pkg/api/login_test.go @@ -64,7 +64,16 @@ type FakeLogger struct { log.Logger } -func (stub *FakeLogger) Info(testMessage string, ctx ...interface{}) { +func (fl *FakeLogger) Debug(testMessage string, ctx ...interface{}) { +} + +func (fl *FakeLogger) Info(testMessage string, ctx ...interface{}) { +} + +func (fl *FakeLogger) Warn(testMessage string, ctx ...interface{}) { +} + +func (fl *FakeLogger) Error(testMessage string, ctx ...interface{}) { } type redirectCase struct { diff --git a/pkg/infra/network/address.go b/pkg/infra/network/address.go new file mode 100644 index 00000000000..a587e68e462 --- /dev/null +++ b/pkg/infra/network/address.go @@ -0,0 +1,44 @@ +package network + +import ( + "fmt" + "net" + "regexp" +) + +var reIPv4AndPort = regexp.MustCompile(`^(\d+\.\d+\.\d+\.\d+):\d+$`) + +// An IPv6 address/port pair can consist of the IP address enclosed in square brackets followed by a colon and +// a port, although the colon/port component is actually optional in practice (e.g., we may receive [::1], where +// we should just strip off the square brackets). +var reIPv6AndPort = regexp.MustCompile(`^\[(.+)\](:\d+)?$`) + +// GetIPFromAddress tries to get an IPv4 or IPv6 address from a host address, potentially including a port. +func GetIPFromAddress(input string) (net.IP, error) { + if a := net.ParseIP(input); len(a) > 0 { + return a, nil + } + + err := fmt.Errorf("not a valid IP address or IP address/port pair: %q", input) + + // It could potentially be an IP address/port pair + var addr string + ms := reIPv4AndPort.FindStringSubmatch(input) + if len(ms) == 0 { + ms := reIPv6AndPort.FindStringSubmatch(input) + if len(ms) == 0 { + return nil, err + } + + addr = ms[1] + } else { + // Strip off port + addr = ms[1] + } + + if a := net.ParseIP(addr); len(a) > 0 { + return a, nil + } + + return nil, err +} diff --git a/pkg/infra/network/address_test.go b/pkg/infra/network/address_test.go new file mode 100644 index 00000000000..89639b58509 --- /dev/null +++ b/pkg/infra/network/address_test.go @@ -0,0 +1,82 @@ +package network + +import ( + "net" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestGetIPFromAddress(t *testing.T) { + testCases := []struct { + desc string + input string + exp string + expErr string + }{ + { + desc: "Valid IPv4", + input: "192.168.2.1", + exp: "192.168.2.1", + }, + { + desc: "Valid IPv6", + input: "2001:0db8:0000:0000:0000:ff00:0042:8329", + exp: "2001:db8::ff00:42:8329", + }, + { + desc: "Valid IPv6 enclosed in square brackets", + input: "[2001:0db8:0000:0000:0000:ff00:0042:8329]", + exp: "2001:db8::ff00:42:8329", + }, + { + desc: "Valid IPv4/port pair", + input: "192.168.2.1:5000", + exp: "192.168.2.1", + }, + { + desc: "Valid IPv6/port pair", + input: "[2001:0db8:0000:0000:0000:ff00:0042:8329]:5000", + exp: "2001:db8::ff00:42:8329", + }, + { + desc: "Invalid IPv6/port pair", + input: "[2001:0db8:0000:0000:0000:ff00:0042:8329]:5000:2000", + expErr: `not a valid IP address or IP address/port pair: "[2001:0db8:0000:0000:0000:ff00:0042:8329]:5000:2000"`, + }, + { + desc: "IPv6 with too many parts", + input: "2001:0db8:0000:0000:0000:ff00:0042:8329:1234", + expErr: `not a valid IP address or IP address/port pair: "2001:0db8:0000:0000:0000:ff00:0042:8329:1234"`, + }, + { + desc: "IPv6 with too few parts", + input: "2001:0db8:0000:0000:0000:ff00:0042", + expErr: `not a valid IP address or IP address/port pair: "2001:0db8:0000:0000:0000:ff00:0042"`, + }, + { + desc: "Valid shortened IPv6", + input: "2001:db8::ff00:42:8329", + exp: "2001:db8::ff00:42:8329", + }, + { + desc: "IPv6 loopback address", + input: "::1", + exp: "::1", + }, + } + for _, tc := range testCases { + t.Run(tc.desc, func(t *testing.T) { + ip, err := GetIPFromAddress(tc.input) + if tc.expErr == "" { + exp := net.ParseIP(tc.exp) + require.NotNil(t, exp) + require.NoError(t, err) + assert.Equal(t, exp, ip) + } else { + require.EqualError(t, err, tc.expErr) + } + }) + } +} diff --git a/pkg/middleware/auth_proxy/auth_proxy.go b/pkg/middleware/auth_proxy/auth_proxy.go index f825038fb8c..6df587a0579 100644 --- a/pkg/middleware/auth_proxy/auth_proxy.go +++ b/pkg/middleware/auth_proxy/auth_proxy.go @@ -132,7 +132,10 @@ func (auth *AuthProxy) IsAllowedIP() (bool, *Error) { proxyObjs = append(proxyObjs, result) } - sourceIP, _, _ := net.SplitHostPort(ip) + sourceIP, _, err := net.SplitHostPort(ip) + if err != nil { + return false, newError("could not parse address", err) + } sourceObj := net.ParseIP(sourceIP) for _, proxyObj := range proxyObjs { @@ -141,11 +144,10 @@ func (auth *AuthProxy) IsAllowedIP() (bool, *Error) { } } - err := fmt.Errorf( + err = fmt.Errorf( "request for user (%s) from %s is not from the authentication proxy", auth.header, sourceIP, ) - return false, newError("Proxy authentication required", err) } diff --git a/pkg/middleware/middleware.go b/pkg/middleware/middleware.go index 5aa3ec061b4..ac82532e52b 100644 --- a/pkg/middleware/middleware.go +++ b/pkg/middleware/middleware.go @@ -14,6 +14,7 @@ import ( "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/components/apikeygen" "github.com/grafana/grafana/pkg/infra/log" + "github.com/grafana/grafana/pkg/infra/network" "github.com/grafana/grafana/pkg/infra/remotecache" "github.com/grafana/grafana/pkg/login" "github.com/grafana/grafana/pkg/models" @@ -255,7 +256,13 @@ func rotateEndOfRequestFunc(ctx *models.ReqContext, authTokenService models.User return } - rotated, err := authTokenService.TryRotateToken(ctx.Req.Context(), token, ctx.RemoteAddr(), ctx.Req.UserAgent()) + addr := ctx.RemoteAddr() + ip, err := network.GetIPFromAddress(addr) + if err != nil { + ctx.Logger.Debug("Failed to get client IP address", "addr", addr, "err", err) + ip = nil + } + rotated, err := authTokenService.TryRotateToken(ctx.Req.Context(), token, ip, ctx.Req.UserAgent()) if err != nil { ctx.Logger.Error("Failed to rotate token", "error", err) return diff --git a/pkg/middleware/middleware_test.go b/pkg/middleware/middleware_test.go index e44f7654ee0..7a996f82c3c 100644 --- a/pkg/middleware/middleware_test.go +++ b/pkg/middleware/middleware_test.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "net" "net/http" "net/http/httptest" "path/filepath" @@ -249,7 +250,8 @@ func TestMiddlewareContext(t *testing.T) { }, nil } - sc.userAuthTokenService.TryRotateTokenProvider = func(ctx context.Context, userToken *models.UserToken, clientIP, userAgent string) (bool, error) { + sc.userAuthTokenService.TryRotateTokenProvider = func(ctx context.Context, userToken *models.UserToken, + clientIP net.IP, userAgent string) (bool, error) { userToken.UnhashedToken = "rotated" return true, nil } @@ -593,7 +595,8 @@ func TestDontRotateTokensOnCancelledRequests(t *testing.T) { tryRotateCallCount := 0 uts := &auth.FakeUserAuthTokenService{ - TryRotateTokenProvider: func(ctx context.Context, token *models.UserToken, clientIP, userAgent string) (bool, error) { + TryRotateTokenProvider: func(ctx context.Context, token *models.UserToken, clientIP net.IP, + userAgent string) (bool, error) { tryRotateCallCount++ return false, nil }, @@ -613,7 +616,8 @@ func TestTokenRotationAtEndOfRequest(t *testing.T) { require.NoError(t, err) uts := &auth.FakeUserAuthTokenService{ - TryRotateTokenProvider: func(ctx context.Context, token *models.UserToken, clientIP, userAgent string) (bool, error) { + TryRotateTokenProvider: func(ctx context.Context, token *models.UserToken, clientIP net.IP, + userAgent string) (bool, error) { newToken, err := util.RandomHex(16) require.NoError(t, err) token.AuthToken = newToken diff --git a/pkg/models/user_token.go b/pkg/models/user_token.go index b07bd508114..d32bda57cec 100644 --- a/pkg/models/user_token.go +++ b/pkg/models/user_token.go @@ -3,6 +3,7 @@ package models import ( "context" "errors" + "net" ) // Typed errors @@ -32,9 +33,9 @@ type RevokeAuthTokenCmd struct { // UserTokenService are used for generating and validating user tokens type UserTokenService interface { - CreateToken(ctx context.Context, userId int64, clientIP, userAgent string) (*UserToken, error) + CreateToken(ctx context.Context, userId int64, clientIP net.IP, userAgent string) (*UserToken, error) LookupToken(ctx context.Context, unhashedToken string) (*UserToken, error) - TryRotateToken(ctx context.Context, token *UserToken, clientIP, userAgent string) (bool, error) + TryRotateToken(ctx context.Context, token *UserToken, clientIP net.IP, userAgent string) (bool, error) RevokeToken(ctx context.Context, token *UserToken) error RevokeAllUserTokens(ctx context.Context, userId int64) error ActiveTokenCount(ctx context.Context) (int64, error) diff --git a/pkg/services/auth/auth_token.go b/pkg/services/auth/auth_token.go index 4396eafbd45..490cacf5888 100644 --- a/pkg/services/auth/auth_token.go +++ b/pkg/services/auth/auth_token.go @@ -4,6 +4,7 @@ import ( "context" "crypto/sha256" "encoding/hex" + "net" "strings" "time" @@ -53,12 +54,7 @@ func (s *UserAuthTokenService) ActiveTokenCount(ctx context.Context) (int64, err return count, err } -func (s *UserAuthTokenService) CreateToken(ctx context.Context, userId int64, clientAddr, userAgent string) (*models.UserToken, error) { - clientIP, err := util.ParseIPAddress(clientAddr) - if err != nil { - s.log.Debug("Failed to parse client IP address", "clientAddr", clientAddr, "err", err) - clientIP = "" - } +func (s *UserAuthTokenService) CreateToken(ctx context.Context, userId int64, clientIP net.IP, userAgent string) (*models.UserToken, error) { token, err := util.RandomHex(16) if err != nil { return nil, err @@ -67,12 +63,16 @@ func (s *UserAuthTokenService) CreateToken(ctx context.Context, userId int64, cl hashedToken := hashToken(token) now := getTime().Unix() + clientIPStr := clientIP.String() + if len(clientIP) == 0 { + clientIPStr = "" + } userAuthToken := userAuthToken{ UserId: userId, AuthToken: hashedToken, PrevAuthToken: hashedToken, - ClientIp: clientIP, + ClientIp: clientIPStr, UserAgent: userAgent, RotatedAt: now, CreatedAt: now, @@ -193,7 +193,7 @@ func (s *UserAuthTokenService) LookupToken(ctx context.Context, unhashedToken st } func (s *UserAuthTokenService) TryRotateToken(ctx context.Context, token *models.UserToken, - clientAddr, userAgent string) (bool, error) { + clientIP net.IP, userAgent string) (bool, error) { if token == nil { return false, nil } @@ -219,12 +219,10 @@ func (s *UserAuthTokenService) TryRotateToken(ctx context.Context, token *models s.log.Debug("token needs rotation", "tokenId", model.Id, "authTokenSeen", model.AuthTokenSeen, "rotatedAt", rotatedAt) - clientIP, err := util.ParseIPAddress(clientAddr) - if err != nil { - s.log.Debug("Failed to parse client IP address", "clientAddr", clientAddr, "err", err) - clientIP = "" + clientIPStr := clientIP.String() + if len(clientIP) == 0 { + clientIPStr = "" } - newToken, err := util.RandomHex(16) if err != nil { return false, err @@ -246,7 +244,9 @@ func (s *UserAuthTokenService) TryRotateToken(ctx context.Context, token *models var affected int64 err = s.SQLStore.WithTransactionalDbSession(ctx, func(dbSession *sqlstore.DBSession) error { - res, err := dbSession.Exec(sql, userAgent, clientIP, s.SQLStore.Dialect.BooleanStr(true), hashedToken, s.SQLStore.Dialect.BooleanStr(false), now.Unix(), model.Id, s.SQLStore.Dialect.BooleanStr(true), now.Add(-30*time.Second).Unix()) + res, err := dbSession.Exec(sql, userAgent, clientIPStr, s.SQLStore.Dialect.BooleanStr(true), hashedToken, + s.SQLStore.Dialect.BooleanStr(false), now.Unix(), model.Id, s.SQLStore.Dialect.BooleanStr(true), + now.Add(-30*time.Second).Unix()) if err != nil { return err } diff --git a/pkg/services/auth/auth_token_test.go b/pkg/services/auth/auth_token_test.go index 617be5ac971..46ae87feb64 100644 --- a/pkg/services/auth/auth_token_test.go +++ b/pkg/services/auth/auth_token_test.go @@ -3,6 +3,7 @@ package auth import ( "context" "encoding/json" + "net" "testing" "time" @@ -27,7 +28,8 @@ func TestUserAuthToken(t *testing.T) { } Convey("When creating token", func() { - userToken, err := userAuthTokenService.CreateToken(context.Background(), userID, "192.168.10.11:1234", "some user agent") + userToken, err := userAuthTokenService.CreateToken(context.Background(), userID, + net.ParseIP("192.168.10.11"), "some user agent") So(err, ShouldBeNil) So(userToken, ShouldNotBeNil) So(userToken.AuthTokenSeen, ShouldBeFalse) @@ -78,7 +80,8 @@ func TestUserAuthToken(t *testing.T) { }) Convey("When creating an additional token", func() { - userToken2, err := userAuthTokenService.CreateToken(context.Background(), userID, "192.168.10.11:1234", "some user agent") + userToken2, err := userAuthTokenService.CreateToken(context.Background(), userID, + net.ParseIP("192.168.10.11"), "some user agent") So(err, ShouldBeNil) So(userToken2, ShouldNotBeNil) @@ -124,7 +127,8 @@ func TestUserAuthToken(t *testing.T) { for i := 0; i < 3; i++ { userId := userID + int64(i+1) userIds = append(userIds, userId) - _, err := userAuthTokenService.CreateToken(context.Background(), userId, "192.168.10.11:1234", "some user agent") + _, err := userAuthTokenService.CreateToken(context.Background(), userId, + net.ParseIP("192.168.10.11"), "some user agent") So(err, ShouldBeNil) } @@ -141,7 +145,8 @@ func TestUserAuthToken(t *testing.T) { }) Convey("expires correctly", func() { - userToken, err := userAuthTokenService.CreateToken(context.Background(), userID, "192.168.10.11:1234", "some user agent") + userToken, err := userAuthTokenService.CreateToken(context.Background(), userID, + net.ParseIP("192.168.10.11"), "some user agent") So(err, ShouldBeNil) userToken, err = userAuthTokenService.LookupToken(context.Background(), userToken.UnhashedToken) @@ -151,7 +156,8 @@ func TestUserAuthToken(t *testing.T) { return t.Add(time.Hour) } - rotated, err := userAuthTokenService.TryRotateToken(context.Background(), userToken, "192.168.10.11:1234", "some user agent") + rotated, err := userAuthTokenService.TryRotateToken(context.Background(), userToken, + net.ParseIP("192.168.10.11"), "some user agent") So(err, ShouldBeNil) So(rotated, ShouldBeTrue) @@ -221,13 +227,15 @@ func TestUserAuthToken(t *testing.T) { }) Convey("can properly rotate tokens", func() { - userToken, err := userAuthTokenService.CreateToken(context.Background(), userID, "192.168.10.11:1234", "some user agent") + userToken, err := userAuthTokenService.CreateToken(context.Background(), userID, + net.ParseIP("192.168.10.11"), "some user agent") So(err, ShouldBeNil) prevToken := userToken.AuthToken unhashedPrev := userToken.UnhashedToken - rotated, err := userAuthTokenService.TryRotateToken(context.Background(), userToken, "192.168.10.12:1234", "a new user agent") + rotated, err := userAuthTokenService.TryRotateToken(context.Background(), userToken, + net.ParseIP("192.168.10.12"), "a new user agent") So(err, ShouldBeNil) So(rotated, ShouldBeFalse) @@ -246,7 +254,8 @@ func TestUserAuthToken(t *testing.T) { return t.Add(time.Hour) } - rotated, err = userAuthTokenService.TryRotateToken(context.Background(), &tok, "192.168.10.12:1234", "a new user agent") + rotated, err = userAuthTokenService.TryRotateToken(context.Background(), &tok, + net.ParseIP("192.168.10.12"), "a new user agent") So(err, ShouldBeNil) So(rotated, ShouldBeTrue) @@ -291,7 +300,8 @@ func TestUserAuthToken(t *testing.T) { So(lookedUpModel, ShouldNotBeNil) So(lookedUpModel.AuthTokenSeen, ShouldBeFalse) - rotated, err = userAuthTokenService.TryRotateToken(context.Background(), userToken, "192.168.10.12:1234", "a new user agent") + rotated, err = userAuthTokenService.TryRotateToken(context.Background(), userToken, + net.ParseIP("192.168.10.12"), "a new user agent") So(err, ShouldBeNil) So(rotated, ShouldBeTrue) @@ -302,7 +312,8 @@ func TestUserAuthToken(t *testing.T) { }) Convey("keeps prev token valid for 1 minute after it is confirmed", func() { - userToken, err := userAuthTokenService.CreateToken(context.Background(), userID, "192.168.10.11:1234", "some user agent") + userToken, err := userAuthTokenService.CreateToken(context.Background(), userID, + net.ParseIP("192.168.10.11"), "some user agent") So(err, ShouldBeNil) So(userToken, ShouldNotBeNil) @@ -315,7 +326,8 @@ func TestUserAuthToken(t *testing.T) { } prevToken := userToken.UnhashedToken - rotated, err := userAuthTokenService.TryRotateToken(context.Background(), userToken, "1.1.1.1", "firefox") + rotated, err := userAuthTokenService.TryRotateToken(context.Background(), userToken, + net.ParseIP("1.1.1.1"), "firefox") So(err, ShouldBeNil) So(rotated, ShouldBeTrue) @@ -333,7 +345,8 @@ func TestUserAuthToken(t *testing.T) { }) Convey("will not mark token unseen when prev and current are the same", func() { - userToken, err := userAuthTokenService.CreateToken(context.Background(), userID, "192.168.10.11:1234", "some user agent") + userToken, err := userAuthTokenService.CreateToken(context.Background(), userID, + net.ParseIP("192.168.10.11"), "some user agent") So(err, ShouldBeNil) So(userToken, ShouldNotBeNil) @@ -352,7 +365,8 @@ func TestUserAuthToken(t *testing.T) { }) Convey("Rotate token", func() { - userToken, err := userAuthTokenService.CreateToken(context.Background(), userID, "192.168.10.11:1234", "some user agent") + userToken, err := userAuthTokenService.CreateToken(context.Background(), userID, + net.ParseIP("192.168.10.11"), "some user agent") So(err, ShouldBeNil) So(userToken, ShouldNotBeNil) @@ -367,7 +381,8 @@ func TestUserAuthToken(t *testing.T) { return t.Add(10 * time.Minute) } - rotated, err := userAuthTokenService.TryRotateToken(context.Background(), userToken, "1.1.1.1", "firefox") + rotated, err := userAuthTokenService.TryRotateToken(context.Background(), userToken, + net.ParseIP("1.1.1.1"), "firefox") So(err, ShouldBeNil) So(rotated, ShouldBeTrue) @@ -388,7 +403,8 @@ func TestUserAuthToken(t *testing.T) { return t.Add(20 * time.Minute) } - rotated, err = userAuthTokenService.TryRotateToken(context.Background(), userToken, "1.1.1.1", "firefox") + rotated, err = userAuthTokenService.TryRotateToken(context.Background(), userToken, + net.ParseIP("1.1.1.1"), "firefox") So(err, ShouldBeNil) So(rotated, ShouldBeTrue) @@ -407,7 +423,8 @@ func TestUserAuthToken(t *testing.T) { return t.Add(2 * time.Minute) } - rotated, err := userAuthTokenService.TryRotateToken(context.Background(), userToken, "1.1.1.1", "firefox") + rotated, err := userAuthTokenService.TryRotateToken(context.Background(), userToken, + net.ParseIP("1.1.1.1"), "firefox") So(err, ShouldBeNil) So(rotated, ShouldBeTrue) diff --git a/pkg/services/auth/testing.go b/pkg/services/auth/testing.go index 4a31f3d9840..d4395ab647a 100644 --- a/pkg/services/auth/testing.go +++ b/pkg/services/auth/testing.go @@ -2,13 +2,14 @@ package auth import ( "context" + "net" "github.com/grafana/grafana/pkg/models" ) type FakeUserAuthTokenService struct { - CreateTokenProvider func(ctx context.Context, userId int64, clientIP, userAgent string) (*models.UserToken, error) - TryRotateTokenProvider func(ctx context.Context, token *models.UserToken, clientIP, userAgent string) (bool, error) + CreateTokenProvider func(ctx context.Context, userId int64, clientIP net.IP, userAgent string) (*models.UserToken, error) + TryRotateTokenProvider func(ctx context.Context, token *models.UserToken, clientIP net.IP, userAgent string) (bool, error) LookupTokenProvider func(ctx context.Context, unhashedToken string) (*models.UserToken, error) RevokeTokenProvider func(ctx context.Context, token *models.UserToken) error RevokeAllUserTokensProvider func(ctx context.Context, userId int64) error @@ -20,13 +21,13 @@ type FakeUserAuthTokenService struct { func NewFakeUserAuthTokenService() *FakeUserAuthTokenService { return &FakeUserAuthTokenService{ - CreateTokenProvider: func(ctx context.Context, userId int64, clientIP, userAgent string) (*models.UserToken, error) { + CreateTokenProvider: func(ctx context.Context, userId int64, clientIP net.IP, userAgent string) (*models.UserToken, error) { return &models.UserToken{ UserId: 0, UnhashedToken: "", }, nil }, - TryRotateTokenProvider: func(ctx context.Context, token *models.UserToken, clientIP, userAgent string) (bool, error) { + TryRotateTokenProvider: func(ctx context.Context, token *models.UserToken, clientIP net.IP, userAgent string) (bool, error) { return false, nil }, LookupTokenProvider: func(ctx context.Context, unhashedToken string) (*models.UserToken, error) { @@ -56,7 +57,8 @@ func NewFakeUserAuthTokenService() *FakeUserAuthTokenService { } } -func (s *FakeUserAuthTokenService) CreateToken(ctx context.Context, userId int64, clientIP, userAgent string) (*models.UserToken, error) { +func (s *FakeUserAuthTokenService) CreateToken(ctx context.Context, userId int64, clientIP net.IP, + userAgent string) (*models.UserToken, error) { return s.CreateTokenProvider(context.Background(), userId, clientIP, userAgent) } @@ -64,7 +66,8 @@ func (s *FakeUserAuthTokenService) LookupToken(ctx context.Context, unhashedToke return s.LookupTokenProvider(context.Background(), unhashedToken) } -func (s *FakeUserAuthTokenService) TryRotateToken(ctx context.Context, token *models.UserToken, clientIP, userAgent string) (bool, error) { +func (s *FakeUserAuthTokenService) TryRotateToken(ctx context.Context, token *models.UserToken, clientIP net.IP, + userAgent string) (bool, error) { return s.TryRotateTokenProvider(context.Background(), token, clientIP, userAgent) } diff --git a/pkg/services/notifications/mailer.go b/pkg/services/notifications/mailer.go index eb30184ea7c..5c8db8191ae 100644 --- a/pkg/services/notifications/mailer.go +++ b/pkg/services/notifications/mailer.go @@ -88,7 +88,6 @@ func (ns *NotificationService) setFiles( func (ns *NotificationService) createDialer() (*gomail.Dialer, error) { host, port, err := net.SplitHostPort(ns.Cfg.Smtp.Host) - if err != nil { return nil, err } diff --git a/pkg/services/sqlstore/sqlstore.go b/pkg/services/sqlstore/sqlstore.go index b790853a6d6..ad67867284d 100644 --- a/pkg/services/sqlstore/sqlstore.go +++ b/pkg/services/sqlstore/sqlstore.go @@ -211,7 +211,9 @@ func (ss *SQLStore) buildConnectionString() (string, error) { if ss.dbCfg.User == "" { ss.dbCfg.User = "''" } - cnnstr = fmt.Sprintf("user=%s password=%s host=%s port=%s dbname=%s sslmode=%s sslcert=%s sslkey=%s sslrootcert=%s", ss.dbCfg.User, ss.dbCfg.Pwd, addr.Host, addr.Port, ss.dbCfg.Name, ss.dbCfg.SslMode, ss.dbCfg.ClientCertPath, ss.dbCfg.ClientKeyPath, ss.dbCfg.CaCertPath) + cnnstr = fmt.Sprintf("user=%s password=%s host=%s port=%s dbname=%s sslmode=%s sslcert=%s sslkey=%s sslrootcert=%s", + ss.dbCfg.User, ss.dbCfg.Pwd, addr.Host, addr.Port, ss.dbCfg.Name, ss.dbCfg.SslMode, ss.dbCfg.ClientCertPath, + ss.dbCfg.ClientKeyPath, ss.dbCfg.CaCertPath) cnnstr += ss.buildExtraConnectionString(' ') case migrator.SQLite: diff --git a/pkg/util/ip_address.go b/pkg/util/ip_address.go index 7fab23ac68a..44694fb0a41 100644 --- a/pkg/util/ip_address.go +++ b/pkg/util/ip_address.go @@ -8,30 +8,6 @@ import ( "github.com/grafana/grafana/pkg/util/errutil" ) -// ParseIPAddress parses an IP address and removes port and/or IPV6 format -func ParseIPAddress(input string) (string, error) { - addr, err := SplitHostPort(input) - if err != nil { - return "", errutil.Wrapf(err, "failed to split network address %q by host and port", - input) - } - - ip := net.ParseIP(addr.Host) - if ip == nil { - return addr.Host, nil - } - - if ip.IsLoopback() { - if strings.Contains(addr.Host, ":") { - // IPv6 - return "::1", nil - } - return "127.0.0.1", nil - } - - return ip.String(), nil -} - type NetworkAddress struct { Host string Port string @@ -79,11 +55,3 @@ func SplitHostPortDefault(input, defaultHost, defaultPort string) (NetworkAddres return addr, nil } - -// SplitHostPort splits ip address/hostname string by host and port -func SplitHostPort(input string) (NetworkAddress, error) { - if len(input) == 0 { - return NetworkAddress{}, fmt.Errorf("input is empty") - } - return SplitHostPortDefault(input, "", "") -} diff --git a/pkg/util/ip_address_test.go b/pkg/util/ip_address_test.go index 79053bfc994..6325fb1d3d5 100644 --- a/pkg/util/ip_address_test.go +++ b/pkg/util/ip_address_test.go @@ -4,52 +4,8 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) -func TestParseIPAddress_Valid(t *testing.T) { - tests := []struct { - input string - expected string - }{ - {input: "127.0.0.1", expected: "127.0.0.1"}, - {input: "192.168.0.140:456", expected: "192.168.0.140"}, - {input: "192.168.0.140", expected: "192.168.0.140"}, - {input: "[::1]:456", expected: "::1"}, - {input: "[::1]", expected: "::1"}, - } - for _, testcase := range tests { - addr, err := ParseIPAddress(testcase.input) - require.NoError(t, err) - assert.Equal(t, testcase.expected, addr) - } -} - -func TestParseIPAddress_Invalid(t *testing.T) { - tests := []struct { - input string - err string - }{ - { - input: "[::1", - err: "failed to split network address \"[::1\" by host and port: malformed IPv6 address: '[::1'", - }, - { - input: "::1]", - err: "failed to split network address \"::1]\" by host and port: net.SplitHostPort failed for '::1]': address ::1]: too many colons in address", - }, - { - input: "", - err: "failed to split network address \"\" by host and port: input is empty", - }, - } - for _, testcase := range tests { - addr, err := ParseIPAddress(testcase.input) - assert.EqualError(t, err, testcase.err) - assert.Empty(t, addr) - } -} - func TestSplitHostPortDefault_Valid(t *testing.T) { tests := []struct { input string @@ -76,25 +32,3 @@ func TestSplitHostPortDefault_Valid(t *testing.T) { assert.Equal(t, testcase.port, addr.Port) } } - -func TestSplitHostPort_Valid(t *testing.T) { - tests := []struct { - input string - host string - port string - }{ - {input: "192.168.0.140:456", host: "192.168.0.140", port: "456"}, - {input: "192.168.0.140", host: "192.168.0.140", port: ""}, - {input: "[::1]:456", host: "::1", port: "456"}, - {input: "[::1]", host: "::1", port: ""}, - {input: ":456", host: "", port: "456"}, - {input: "xyz.rds.amazonaws.com", host: "xyz.rds.amazonaws.com", port: ""}, - {input: "xyz.rds.amazonaws.com:123", host: "xyz.rds.amazonaws.com", port: "123"}, - } - for _, testcase := range tests { - addr, err := SplitHostPort(testcase.input) - require.NoError(t, err) - assert.Equal(t, testcase.host, addr.Host) - assert.Equal(t, testcase.port, addr.Port) - } -}