2021-08-16 23:30:51 +02:00
package server
2021-07-17 14:38:59 +02:00
import (
"context"
2021-07-30 17:46:38 +02:00
"fmt"
2022-05-08 11:04:57 +02:00
"strings"
2021-07-24 16:14:29 +02:00
"time"
2022-05-21 15:21:39 +02:00
"github.com/netbirdio/netbird/management/server/http/middleware"
"github.com/netbirdio/netbird/management/server/jwtclaims"
2021-07-22 10:28:00 +02:00
"github.com/golang/protobuf/ptypes/timestamp"
2022-03-26 12:08:54 +01:00
"github.com/netbirdio/netbird/encryption"
"github.com/netbirdio/netbird/management/proto"
2021-07-22 10:28:00 +02:00
log "github.com/sirupsen/logrus"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
"google.golang.org/grpc/codes"
2021-07-17 14:38:59 +02:00
"google.golang.org/grpc/status"
)
// Server an instance of a Management server
type Server struct {
2022-02-22 11:28:19 +01:00
accountManager AccountManager
2021-07-30 17:46:38 +02:00
wgKey wgtypes . Key
2021-07-20 18:09:26 +02:00
proto . UnimplementedManagementServiceServer
2021-09-02 14:41:54 +02:00
peersUpdateManager * PeersUpdateManager
config * Config
turnCredentialsManager TURNCredentialsManager
2022-05-05 20:02:15 +02:00
jwtMiddleware * middleware . JWTMiddleware
2021-07-22 10:28:00 +02:00
}
2021-07-17 14:38:59 +02:00
// NewServer creates a new Management server
2022-02-22 11:28:19 +01:00
func NewServer ( config * Config , accountManager AccountManager , peersUpdateManager * PeersUpdateManager , turnCredentialsManager TURNCredentialsManager ) ( * Server , error ) {
2021-07-22 10:28:00 +02:00
key , err := wgtypes . GeneratePrivateKey ( )
if err != nil {
return nil , err
}
2021-08-29 17:48:31 +02:00
2022-05-05 20:02:15 +02:00
var jwtMiddleware * middleware . JWTMiddleware
if config . HttpConfig != nil && config . HttpConfig . AuthIssuer != "" && config . HttpConfig . AuthAudience != "" && validateURL ( config . HttpConfig . AuthKeysLocation ) {
jwtMiddleware , err = middleware . NewJwtMiddleware (
config . HttpConfig . AuthIssuer ,
config . HttpConfig . AuthAudience ,
config . HttpConfig . AuthKeysLocation )
if err != nil {
return nil , status . Errorf ( codes . Internal , "unable to create new jwt middleware, err: %v" , err )
}
2022-05-08 11:04:57 +02:00
} else {
log . Debug ( "unable to use http config to create new jwt middleware" )
2022-05-05 20:02:15 +02:00
}
2021-07-17 14:38:59 +02:00
return & Server {
2021-07-22 10:28:00 +02:00
wgKey : key ,
// peerKey -> event channel
2021-09-02 14:41:54 +02:00
peersUpdateManager : peersUpdateManager ,
accountManager : accountManager ,
config : config ,
turnCredentialsManager : turnCredentialsManager ,
2022-05-05 20:02:15 +02:00
jwtMiddleware : jwtMiddleware ,
2021-07-17 14:38:59 +02:00
} , nil
}
2021-07-22 10:28:00 +02:00
func ( s * Server ) GetServerKey ( ctx context . Context , req * proto . Empty ) ( * proto . ServerKeyResponse , error ) {
// todo introduce something more meaningful with the key expiration/rotation
now := time . Now ( ) . Add ( 24 * time . Hour )
secs := int64 ( now . Second ( ) )
nanos := int32 ( now . Nanosecond ( ) )
expiresAt := & timestamp . Timestamp { Seconds : secs , Nanos : nanos }
return & proto . ServerKeyResponse {
Key : s . wgKey . PublicKey ( ) . String ( ) ,
ExpiresAt : expiresAt ,
} , nil
}
2022-05-21 15:21:39 +02:00
// Sync validates the existence of a connecting peer, sends an initial state (all available for the connecting peers) and
2021-07-22 10:28:00 +02:00
// notifies the connected peer of any updates (e.g. new peers under the same account)
func ( s * Server ) Sync ( req * proto . EncryptedMessage , srv proto . ManagementService_SyncServer ) error {
log . Debugf ( "Sync request from peer %s" , req . WgPubKey )
peerKey , err := wgtypes . ParseKey ( req . GetWgPubKey ( ) )
if err != nil {
log . Warnf ( "error while parsing peer's Wireguard public key %s on Sync request." , peerKey . String ( ) )
return status . Errorf ( codes . InvalidArgument , "provided wgPubKey %s is invalid" , peerKey . String ( ) )
}
2021-07-30 17:46:38 +02:00
peer , err := s . accountManager . GetPeer ( peerKey . String ( ) )
if err != nil {
2021-08-15 16:56:26 +02:00
return status . Errorf ( codes . PermissionDenied , "provided peer with the key wgPubKey %s is not registered" , peerKey . String ( ) )
2021-07-22 10:28:00 +02:00
}
syncReq := & proto . SyncRequest { }
2021-07-22 15:23:24 +02:00
err = encryption . DecryptMessage ( peerKey , s . wgKey , req . Body , syncReq )
2021-07-22 10:28:00 +02:00
if err != nil {
return status . Errorf ( codes . InvalidArgument , "invalid request message" )
}
2021-07-30 17:46:38 +02:00
err = s . sendInitialSync ( peerKey , peer , srv )
2021-07-22 10:28:00 +02:00
if err != nil {
return err
}
2021-08-29 17:48:31 +02:00
updates := s . peersUpdateManager . CreateChannel ( peerKey . String ( ) )
err = s . accountManager . MarkPeerConnected ( peerKey . String ( ) , true )
if err != nil {
log . Warnf ( "failed marking peer as connected %s %v" , peerKey , err )
}
2021-09-02 14:41:54 +02:00
2021-09-03 17:47:40 +02:00
if s . config . TURNConfig . TimeBasedCredentials {
s . turnCredentialsManager . SetupRefresh ( peerKey . String ( ) )
}
2021-07-22 10:28:00 +02:00
// keep a connection to the peer and send updates when available
for {
select {
// condition when there are some updates
case update , open := <- updates :
if ! open {
// updates channel has been closed
return nil
}
log . Debugf ( "recevied an update for peer %s" , peerKey . String ( ) )
2021-07-22 15:23:24 +02:00
encryptedResp , err := encryption . EncryptMessage ( peerKey , s . wgKey , update . Update )
2021-07-22 10:28:00 +02:00
if err != nil {
return status . Errorf ( codes . Internal , "failed processing update message" )
}
2021-07-22 15:23:24 +02:00
err = srv . SendMsg ( & proto . EncryptedMessage {
WgPubKey : s . wgKey . PublicKey ( ) . String ( ) ,
Body : encryptedResp ,
} )
2021-07-22 10:28:00 +02:00
if err != nil {
return status . Errorf ( codes . Internal , "failed sending update message" )
}
2021-09-07 18:36:46 +02:00
log . Debugf ( "sent an update to peer %s" , peerKey . String ( ) )
2021-07-22 10:28:00 +02:00
// condition when client <-> server connection has been terminated
case <- srv . Context ( ) . Done ( ) :
// happens when connection drops, e.g. client disconnects
log . Debugf ( "stream of peer %s has been closed" , peerKey . String ( ) )
2021-08-29 17:48:31 +02:00
s . peersUpdateManager . CloseChannel ( peerKey . String ( ) )
2021-09-02 14:41:54 +02:00
s . turnCredentialsManager . CancelRefresh ( peerKey . String ( ) )
err = s . accountManager . MarkPeerConnected ( peerKey . String ( ) , false )
2021-08-29 17:48:31 +02:00
if err != nil {
log . Warnf ( "failed marking peer as disconnected %s %v" , peerKey , err )
}
// todo stop turn goroutine
2021-07-22 10:28:00 +02:00
return srv . Context ( ) . Err ( )
}
}
}
2021-08-24 11:50:19 +02:00
func ( s * Server ) registerPeer ( peerKey wgtypes . Key , req * proto . LoginRequest ) ( * Peer , error ) {
2022-05-05 20:02:15 +02:00
var (
reqSetupKey string
userId string
)
if req . GetJwtToken ( ) != "" {
log . Debugln ( "using jwt token to register peer" )
if s . jwtMiddleware == nil {
return nil , status . Error ( codes . Internal , "no jwt middleware set" )
}
token , err := s . jwtMiddleware . ValidateAndParse ( req . GetJwtToken ( ) )
if err != nil {
return nil , status . Errorf ( codes . Internal , "invalid jwt token, err: %v" , err )
}
claims := jwtclaims . ExtractClaimsWithToken ( token , s . config . HttpConfig . AuthAudience )
_ , err = s . accountManager . GetAccountWithAuthorizationClaims ( claims )
if err != nil {
return nil , status . Errorf ( codes . Internal , "unable to fetch account with claims, err: %v" , err )
}
userId = claims . UserId
} else {
log . Debugln ( "using setup key to register peer" )
reqSetupKey = req . GetSetupKey ( )
userId = ""
}
2021-08-24 11:50:19 +02:00
meta := req . GetMeta ( )
if meta == nil {
return nil , status . Errorf ( codes . InvalidArgument , "peer meta data was not provided" )
}
2022-05-25 23:25:02 +02:00
2022-06-23 17:04:53 +02:00
var sshKey [ ] byte
if req . GetPeerKeys ( ) != nil {
sshKey = req . GetPeerKeys ( ) . GetSshPubKey ( )
}
2022-05-05 20:02:15 +02:00
peer , err := s . accountManager . AddPeer ( reqSetupKey , userId , & Peer {
2022-06-23 17:04:53 +02:00
Key : peerKey . String ( ) ,
Name : meta . GetHostname ( ) ,
SSHKey : string ( sshKey ) ,
2021-08-24 11:50:19 +02:00
Meta : PeerSystemMeta {
Hostname : meta . GetHostname ( ) ,
GoOS : meta . GetGoOS ( ) ,
Kernel : meta . GetKernel ( ) ,
Core : meta . GetCore ( ) ,
Platform : meta . GetPlatform ( ) ,
OS : meta . GetOS ( ) ,
WtVersion : meta . GetWiretrusteeVersion ( ) ,
2022-05-25 23:25:02 +02:00
UIVersion : meta . GetUiVersion ( ) ,
2021-08-24 11:50:19 +02:00
} ,
} )
2021-07-17 14:38:59 +02:00
if err != nil {
2022-06-02 12:56:02 +02:00
s , ok := status . FromError ( err )
if ok {
if s . Code ( ) == codes . FailedPrecondition || s . Code ( ) == codes . OutOfRange {
return nil , err
}
2022-05-12 11:17:24 +02:00
}
2021-08-15 16:56:26 +02:00
return nil , status . Errorf ( codes . NotFound , "provided setup key doesn't exists" )
2021-07-22 10:28:00 +02:00
}
2022-05-21 15:21:39 +02:00
// todo move to DefaultAccountManager the code below
2022-01-16 17:10:36 +01:00
networkMap , err := s . accountManager . GetNetworkMap ( peer . Key )
2021-07-22 10:28:00 +02:00
if err != nil {
2022-05-05 20:02:15 +02:00
return nil , status . Errorf ( codes . Internal , "unable to fetch network map after registering peer, error: %v" , err )
2021-07-22 10:28:00 +02:00
}
// notify other peers of our registration
2022-01-16 17:10:36 +01:00
for _ , remotePeer := range networkMap . Peers {
2021-08-29 17:48:31 +02:00
// exclude notified peer and add ourselves
peersToSend := [ ] * Peer { peer }
2022-01-16 17:10:36 +01:00
for _ , p := range networkMap . Peers {
2021-08-29 17:48:31 +02:00
if remotePeer . Key != p . Key {
peersToSend = append ( peersToSend , p )
2021-07-22 10:28:00 +02:00
}
2021-08-29 17:48:31 +02:00
}
2022-06-04 19:41:01 +02:00
update := toSyncResponse ( s . config , remotePeer , peersToSend , nil , networkMap . Network . CurrentSerial ( ) )
2021-08-29 17:48:31 +02:00
err = s . peersUpdateManager . SendUpdate ( remotePeer . Key , & UpdateMessage { Update : update } )
if err != nil {
// todo rethink if we should keep this return
2022-05-05 20:02:15 +02:00
return nil , status . Errorf ( codes . Internal , "unable to send update after registering peer, error: %v" , err )
2021-07-22 10:28:00 +02:00
}
2021-07-17 14:38:59 +02:00
}
2021-08-15 16:56:26 +02:00
return peer , nil
}
// Login endpoint first checks whether peer is registered under any account
// In case it is, the login is successful
// In case it isn't, the endpoint checks whether setup key is provided within the request and tries to register a peer.
// In case of the successful registration login is also successful
func ( s * Server ) Login ( ctx context . Context , req * proto . EncryptedMessage ) ( * proto . EncryptedMessage , error ) {
log . Debugf ( "Login request from peer %s" , req . WgPubKey )
peerKey , err := wgtypes . ParseKey ( req . GetWgPubKey ( ) )
if err != nil {
log . Warnf ( "error while parsing peer's Wireguard public key %s on Sync request." , req . WgPubKey )
return nil , status . Errorf ( codes . InvalidArgument , "provided wgPubKey %s is invalid" , req . WgPubKey )
}
2022-05-23 13:03:57 +02:00
loginReq := & proto . LoginRequest { }
err = encryption . DecryptMessage ( peerKey , s . wgKey , req . Body , loginReq )
if err != nil {
return nil , status . Errorf ( codes . InvalidArgument , "invalid request message" )
}
2021-08-15 16:56:26 +02:00
peer , err := s . accountManager . GetPeer ( peerKey . String ( ) )
if err != nil {
if errStatus , ok := status . FromError ( err ) ; ok && errStatus . Code ( ) == codes . NotFound {
2022-05-21 15:21:39 +02:00
// peer doesn't exist -> check if setup key was provided
2022-05-05 20:02:15 +02:00
if loginReq . GetJwtToken ( ) == "" && loginReq . GetSetupKey ( ) == "" {
2022-05-21 15:21:39 +02:00
// absent setup key -> permission denied
2022-05-05 20:02:15 +02:00
return nil , status . Errorf ( codes . PermissionDenied , "provided peer with the key wgPubKey %s is not registered and no setup key or jwt was provided" , peerKey . String ( ) )
2021-08-15 16:56:26 +02:00
}
2022-05-21 15:21:39 +02:00
// setup key or jwt is present -> try normal registration flow
2021-08-24 11:50:19 +02:00
peer , err = s . registerPeer ( peerKey , loginReq )
2021-08-15 16:56:26 +02:00
if err != nil {
return nil , err
}
} else {
return nil , status . Error ( codes . Internal , "internal server error" )
}
2022-05-23 13:03:57 +02:00
} else if loginReq . GetMeta ( ) != nil {
// update peer's system meta data on Login
err = s . accountManager . UpdatePeerMeta ( peerKey . String ( ) , PeerSystemMeta {
Hostname : loginReq . GetMeta ( ) . GetHostname ( ) ,
GoOS : loginReq . GetMeta ( ) . GetGoOS ( ) ,
Kernel : loginReq . GetMeta ( ) . GetKernel ( ) ,
Core : loginReq . GetMeta ( ) . GetCore ( ) ,
Platform : loginReq . GetMeta ( ) . GetPlatform ( ) ,
OS : loginReq . GetMeta ( ) . GetOS ( ) ,
2022-05-25 23:25:02 +02:00
WtVersion : loginReq . GetMeta ( ) . GetWiretrusteeVersion ( ) ,
UIVersion : loginReq . GetMeta ( ) . GetUiVersion ( ) ,
} ,
)
2022-05-23 13:03:57 +02:00
if err != nil {
log . Errorf ( "failed updating peer system meta data %s" , peerKey . String ( ) )
return nil , status . Error ( codes . Internal , "internal server error" )
}
2021-08-15 16:56:26 +02:00
}
2022-06-23 17:04:53 +02:00
var sshKey [ ] byte
if loginReq . GetPeerKeys ( ) != nil {
sshKey = loginReq . GetPeerKeys ( ) . GetSshPubKey ( )
}
if len ( sshKey ) > 0 {
err = s . accountManager . UpdatePeerSSHKey ( peerKey . String ( ) , string ( sshKey ) )
if err != nil {
return nil , err
}
}
2021-08-15 16:56:26 +02:00
// if peer has reached this point then it has logged in
loginResp := & proto . LoginResponse {
2021-09-02 14:41:54 +02:00
WiretrusteeConfig : toWiretrusteeConfig ( s . config , nil ) ,
2021-08-15 16:56:26 +02:00
PeerConfig : toPeerConfig ( peer ) ,
}
encryptedResp , err := encryption . EncryptMessage ( peerKey , s . wgKey , loginResp )
if err != nil {
return nil , status . Errorf ( codes . Internal , "failed logging in peer" )
}
return & proto . EncryptedMessage {
WgPubKey : s . wgKey . PublicKey ( ) . String ( ) ,
Body : encryptedResp ,
} , nil
2021-07-17 14:38:59 +02:00
}
2021-09-02 14:41:54 +02:00
func ToResponseProto ( configProto Protocol ) proto . HostConfig_Protocol {
2021-07-30 17:46:38 +02:00
switch configProto {
2021-08-16 23:30:51 +02:00
case UDP :
2021-07-30 17:46:38 +02:00
return proto . HostConfig_UDP
2021-08-16 23:30:51 +02:00
case DTLS :
2021-07-30 17:46:38 +02:00
return proto . HostConfig_DTLS
2021-08-16 23:30:51 +02:00
case HTTP :
2021-07-30 17:46:38 +02:00
return proto . HostConfig_HTTP
2021-08-16 23:30:51 +02:00
case HTTPS :
2021-07-30 17:46:38 +02:00
return proto . HostConfig_HTTPS
2021-08-16 23:30:51 +02:00
case TCP :
2021-07-30 17:46:38 +02:00
return proto . HostConfig_TCP
default :
2022-05-21 15:21:39 +02:00
// mbragin: todo something better?
2021-07-30 17:46:38 +02:00
panic ( fmt . Errorf ( "unexpected config protocol type %v" , configProto ) )
}
}
2021-09-02 14:41:54 +02:00
func toWiretrusteeConfig ( config * Config , turnCredentials * TURNCredentials ) * proto . WiretrusteeConfig {
2021-07-30 17:46:38 +02:00
var stuns [ ] * proto . HostConfig
for _ , stun := range config . Stuns {
stuns = append ( stuns , & proto . HostConfig {
Uri : stun . URI ,
2021-09-02 14:41:54 +02:00
Protocol : ToResponseProto ( stun . Proto ) ,
2021-07-30 17:46:38 +02:00
} )
}
var turns [ ] * proto . ProtectedHostConfig
2021-09-02 14:41:54 +02:00
for _ , turn := range config . TURNConfig . Turns {
var username string
var password string
if turnCredentials != nil {
username = turnCredentials . Username
password = turnCredentials . Password
} else {
username = turn . Username
2021-09-07 18:36:46 +02:00
password = turn . Password
2021-09-02 14:41:54 +02:00
}
2021-07-30 17:46:38 +02:00
turns = append ( turns , & proto . ProtectedHostConfig {
HostConfig : & proto . HostConfig {
Uri : turn . URI ,
2021-09-02 14:41:54 +02:00
Protocol : ToResponseProto ( turn . Proto ) ,
2021-07-30 17:46:38 +02:00
} ,
2021-09-02 14:41:54 +02:00
User : username ,
Password : password ,
2021-07-30 17:46:38 +02:00
} )
}
2021-08-15 16:56:26 +02:00
return & proto . WiretrusteeConfig {
2021-07-30 17:46:38 +02:00
Stuns : stuns ,
Turns : turns ,
Signal : & proto . HostConfig {
Uri : config . Signal . URI ,
2021-09-02 14:41:54 +02:00
Protocol : ToResponseProto ( config . Signal . Proto ) ,
2021-07-30 17:46:38 +02:00
} ,
}
2021-08-15 16:56:26 +02:00
}
2021-07-30 17:46:38 +02:00
2021-08-16 23:30:51 +02:00
func toPeerConfig ( peer * Peer ) * proto . PeerConfig {
2021-08-15 16:56:26 +02:00
return & proto . PeerConfig {
2022-06-23 17:04:53 +02:00
Address : fmt . Sprintf ( "%s/%d" , peer . IP . String ( ) , SubnetSize ) , // take it from the network
SshConfig : & proto . SSHConfig { SshEnabled : peer . SSHEnabled } ,
2021-07-30 17:46:38 +02:00
}
2021-08-15 16:56:26 +02:00
}
2021-09-07 18:36:46 +02:00
func toRemotePeerConfig ( peers [ ] * Peer ) [ ] * proto . RemotePeerConfig {
remotePeers := [ ] * proto . RemotePeerConfig { }
2021-07-30 17:46:38 +02:00
for _ , rPeer := range peers {
remotePeers = append ( remotePeers , & proto . RemotePeerConfig {
WgPubKey : rPeer . Key ,
2022-06-04 19:41:01 +02:00
AllowedIps : [ ] string { fmt . Sprintf ( AllowedIPsFormat , rPeer . IP ) } ,
2022-06-23 17:04:53 +02:00
SshConfig : & proto . SSHConfig { SshPubKey : [ ] byte ( rPeer . SSHKey ) } ,
2021-07-30 17:46:38 +02:00
} )
}
2021-09-07 18:36:46 +02:00
return remotePeers
}
2022-01-16 17:10:36 +01:00
func toSyncResponse ( config * Config , peer * Peer , peers [ ] * Peer , turnCredentials * TURNCredentials , serial uint64 ) * proto . SyncResponse {
2021-09-07 18:36:46 +02:00
wtConfig := toWiretrusteeConfig ( config , turnCredentials )
pConfig := toPeerConfig ( peer )
remotePeers := toRemotePeerConfig ( peers )
2021-07-30 17:46:38 +02:00
return & proto . SyncResponse {
2021-09-07 18:36:46 +02:00
WiretrusteeConfig : wtConfig ,
PeerConfig : pConfig ,
RemotePeers : remotePeers ,
RemotePeersIsEmpty : len ( remotePeers ) == 0 ,
2022-01-16 17:10:36 +01:00
NetworkMap : & proto . NetworkMap {
Serial : serial ,
PeerConfig : pConfig ,
RemotePeers : remotePeers ,
RemotePeersIsEmpty : len ( remotePeers ) == 0 ,
} ,
2021-07-30 17:46:38 +02:00
}
}
2021-07-17 14:38:59 +02:00
// IsHealthy indicates whether the service is healthy
func ( s * Server ) IsHealthy ( ctx context . Context , req * proto . Empty ) ( * proto . Empty , error ) {
return & proto . Empty { } , nil
}
2021-07-22 10:28:00 +02:00
// sendInitialSync sends initial proto.SyncResponse to the peer requesting synchronization
2021-08-16 23:30:51 +02:00
func ( s * Server ) sendInitialSync ( peerKey wgtypes . Key , peer * Peer , srv proto . ManagementService_SyncServer ) error {
2022-01-16 17:10:36 +01:00
networkMap , err := s . accountManager . GetNetworkMap ( peer . Key )
2021-07-22 10:28:00 +02:00
if err != nil {
2021-07-30 17:46:38 +02:00
log . Warnf ( "error getting a list of peers for a peer %s" , peer . Key )
2021-07-22 10:28:00 +02:00
return err
}
2021-09-02 14:41:54 +02:00
// make secret time based TURN credentials optional
var turnCredentials * TURNCredentials
if s . config . TURNConfig . TimeBasedCredentials {
creds := s . turnCredentialsManager . GenerateCredentials ( )
turnCredentials = & creds
} else {
turnCredentials = nil
}
2022-03-10 18:18:38 +01:00
plainResp := toSyncResponse ( s . config , peer , networkMap . Peers , turnCredentials , networkMap . Network . CurrentSerial ( ) )
2021-07-22 10:28:00 +02:00
2021-07-22 15:23:24 +02:00
encryptedResp , err := encryption . EncryptMessage ( peerKey , s . wgKey , plainResp )
2021-07-22 10:28:00 +02:00
if err != nil {
return status . Errorf ( codes . Internal , "error handling request" )
}
2021-09-02 14:41:54 +02:00
2021-07-22 15:23:24 +02:00
err = srv . Send ( & proto . EncryptedMessage {
WgPubKey : s . wgKey . PublicKey ( ) . String ( ) ,
Body : encryptedResp ,
} )
2021-07-22 10:28:00 +02:00
if err != nil {
log . Errorf ( "failed sending SyncResponse %v" , err )
return status . Errorf ( codes . Internal , "error handling request" )
}
return nil
}
2022-05-08 11:04:57 +02:00
// GetDeviceAuthorizationFlow returns a device authorization flow information
// This is used for initiating an Oauth 2 device authorization grant flow
// which will be used by our clients to Login
func ( s * Server ) GetDeviceAuthorizationFlow ( ctx context . Context , req * proto . EncryptedMessage ) ( * proto . EncryptedMessage , error ) {
peerKey , err := wgtypes . ParseKey ( req . GetWgPubKey ( ) )
if err != nil {
errMSG := fmt . Sprintf ( "error while parsing peer's Wireguard public key %s on GetDeviceAuthorizationFlow request." , req . WgPubKey )
log . Warn ( errMSG )
return nil , status . Error ( codes . InvalidArgument , errMSG )
}
err = encryption . DecryptMessage ( peerKey , s . wgKey , req . Body , & proto . DeviceAuthorizationFlowRequest { } )
if err != nil {
errMSG := fmt . Sprintf ( "error while decrypting peer's message with Wireguard public key %s." , req . WgPubKey )
log . Warn ( errMSG )
return nil , status . Error ( codes . InvalidArgument , errMSG )
}
if s . config . DeviceAuthorizationFlow == nil {
return nil , status . Error ( codes . NotFound , "no device authorization flow information available" )
}
provider , ok := proto . DeviceAuthorizationFlowProvider_value [ strings . ToUpper ( s . config . DeviceAuthorizationFlow . Provider ) ]
if ! ok {
return nil , status . Errorf ( codes . InvalidArgument , "no provider found in the protocol for %s" , s . config . DeviceAuthorizationFlow . Provider )
}
flowInfoResp := & proto . DeviceAuthorizationFlow {
Provider : proto . DeviceAuthorizationFlowProvider ( provider ) ,
ProviderConfig : & proto . ProviderConfig {
ClientID : s . config . DeviceAuthorizationFlow . ProviderConfig . ClientID ,
ClientSecret : s . config . DeviceAuthorizationFlow . ProviderConfig . ClientSecret ,
Domain : s . config . DeviceAuthorizationFlow . ProviderConfig . Domain ,
Audience : s . config . DeviceAuthorizationFlow . ProviderConfig . Audience ,
} ,
}
encryptedResp , err := encryption . EncryptMessage ( peerKey , s . wgKey , flowInfoResp )
if err != nil {
return nil , status . Error ( codes . Internal , "failed to encrypt no device authorization flow information" )
}
return & proto . EncryptedMessage {
WgPubKey : s . wgKey . PublicKey ( ) . String ( ) ,
Body : encryptedResp ,
} , nil
}