Skip to content
This repository has been archived by the owner on Dec 14, 2021. It is now read-only.

Commit

Permalink
Merge pull request #400 from TheThingsNetwork/issue/392-authenticated…
Browse files Browse the repository at this point in the history
…-gateways

Add auth/trust for gateways
  • Loading branch information
htdvisser authored Jan 10, 2017
2 parents 50e54e2 + f1bb6e0 commit 47c74df
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 78 deletions.
176 changes: 124 additions & 52 deletions api/gateway/gateway.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions api/gateway/gateway.proto
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ message GPSMetadata {
message RxMetadata {
string gateway_id = 1;

// Indicates whether the gateway is trusted. Components that are able to verify gateway trust MUST do so and set this value accordingly
bool gateway_trusted = 2;

// Timestamp (uptime of LoRa module) in microseconds with rollover
uint32 timestamp = 11;
// Time in Unix nanoseconds
Expand Down Expand Up @@ -63,6 +66,9 @@ message Status {
// Time in Unix nanoseconds
int64 time = 2;

// Indicates whether the gateway is trusted. Components that are able to verify gateway trust MUST do so and set this value accordingly
bool gateway_trusted = 3;

// Configuration and relatively static stuff
// These values may be left out if they don't change
// Reset using "-"
Expand Down
15 changes: 8 additions & 7 deletions core/handler/convert_metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,14 @@ func (h *handler) ConvertMetadata(ctx log.Interface, ttnUp *pb_broker.Deduplicat
}

gatewayMetadata := types.GatewayMetadata{
GtwID: in.GatewayId,
Timestamp: in.Timestamp,
Time: types.BuildTime(in.Time),
Channel: in.Channel,
RFChain: in.RfChain,
RSSI: in.Rssi,
SNR: in.Snr,
GtwID: in.GatewayId,
GtwTrusted: in.GatewayTrusted,
Timestamp: in.Timestamp,
Time: types.BuildTime(in.Time),
Channel: in.Channel,
RFChain: in.RfChain,
RSSI: in.Rssi,
SNR: in.Snr,
}

if gps := in.GetGps(); gps != nil {
Expand Down
18 changes: 16 additions & 2 deletions core/router/gateway/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package gateway

import (
"sync"
"time"

pb "github.com/TheThingsNetwork/ttn/api/gateway"
Expand Down Expand Up @@ -32,14 +33,19 @@ type Gateway struct {
Schedule Schedule
LastSeen time.Time

token string
mu sync.RWMutex // Protect token and authenticated
token string
authenticated bool

Monitors map[string]pb_monitor.GatewayClient

Ctx log.Interface
}

func (g *Gateway) SetToken(token string) {
func (g *Gateway) SetAuth(token string, authenticated bool) {
g.mu.Lock()
defer g.mu.Unlock()
g.authenticated = authenticated
if token == g.token {
return
}
Expand All @@ -54,6 +60,9 @@ func (g *Gateway) updateLastSeen() {
}

func (g *Gateway) HandleStatus(status *pb.Status) (err error) {
g.mu.RLock()
defer g.mu.RUnlock()
status.GatewayTrusted = g.authenticated
if err = g.Status.Update(status); err != nil {
return err
}
Expand Down Expand Up @@ -81,6 +90,11 @@ func (g *Gateway) HandleUplink(uplink *pb_router.UplinkMessage) (err error) {
}
}

// Inject authenticated as GatewayTrusted
g.mu.RLock()
defer g.mu.RUnlock()
uplink.GatewayMetadata.GatewayTrusted = g.authenticated

if g.Monitors != nil {
for _, monitor := range g.Monitors {
go monitor.SendUplink(uplink)
Expand Down
27 changes: 17 additions & 10 deletions core/router/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,26 +37,33 @@ func (r *routerRPC) gatewayFromMetadata(md metadata.MD) (gtw *gateway.Gateway, e
return nil, err
}

authErr := errors.NewErrPermissionDenied("Gateway not authenticated")
authenticated := false
token, _ := api.TokenFromMetadata(md)

if !viper.GetBool("router.skip-verify-gateway-token") {
if token == "" {
return nil, errors.NewErrPermissionDenied("No gateway token supplied")
}
if token != "" {
if r.router.TokenKeyProvider == nil {
return nil, errors.NewErrInternal("No token provider configured")
}
claims, err := claims.FromToken(r.router.TokenKeyProvider, token)
claims, err := claims.FromGatewayToken(r.router.TokenKeyProvider, token)
if err != nil {
return nil, errors.NewErrPermissionDenied(fmt.Sprintf("Gateway token invalid: %s", err.Error()))
}
if claims.Type != "gateway" || claims.Subject != gatewayID {
return nil, errors.NewErrPermissionDenied("Gateway token not consistent")
authErr = errors.NewErrPermissionDenied(fmt.Sprintf("Gateway token invalid: %s", err))
} else {
if claims.Subject != gatewayID {
authErr = errors.NewErrPermissionDenied(fmt.Sprintf("Token subject \"%s\" not consistent with gateway ID \"%s\"", claims.Subject, gatewayID))
} else {
authErr = nil
authenticated = true
}
}
}

if authErr != nil && !viper.GetBool("router.skip-verify-gateway-token") {
return nil, authErr
}

gtw = r.router.getGateway(gatewayID)
gtw.SetToken(token)
gtw.SetAuth(token, authenticated)

return gtw, nil
}
Expand Down
15 changes: 8 additions & 7 deletions core/types/gateway_metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ package types

// GatewayMetadata contains metadata for each gateway that received a message
type GatewayMetadata struct {
GtwID string `json:"gtw_id,omitempty"`
Timestamp uint32 `json:"timestamp,omitempty"`
Time JSONTime `json:"time,omitempty"`
Channel uint32 `json:"channel"`
RSSI float32 `json:"rssi,omitempty"`
SNR float32 `json:"snr,omitempty"`
RFChain uint32 `json:"rf_chain,omitempty"`
GtwID string `json:"gtw_id,omitempty"`
GtwTrusted bool `json:"gtw_trusted,omitempty"`
Timestamp uint32 `json:"timestamp,omitempty"`
Time JSONTime `json:"time,omitempty"`
Channel uint32 `json:"channel"`
RSSI float32 `json:"rssi,omitempty"`
SNR float32 `json:"snr,omitempty"`
RFChain uint32 `json:"rf_chain,omitempty"`
LocationMetadata
}

0 comments on commit 47c74df

Please sign in to comment.