eintopf.info@v0.13.16/service/auth/auth_test.go (about)

     1  // Copyright (C) 2022 The Eintopf authors
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <https://www.gnu.org/licenses/>.
    15  
    16  package auth_test
    17  
    18  import (
    19  	"context"
    20  	"fmt"
    21  	"testing"
    22  	"time"
    23  
    24  	"eintopf.info/service/auth"
    25  )
    26  
    27  var privateKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
    28  MIICXAIBAAKBgQCGGYYvHAZvjOVC6NtJNu42nwb1tvl1bhmgpwxg5gpnce0cuGK8
    29  N4kky86sOpuUDmRCCoXCyR8l5wEE+XOluf0NOIEg8cA0w1+je60bVztDCK/IAlI9
    30  szfdV7s0sFVgvb+SqoR6ADxmdPKnsIpqQfAYOSzwjMm/yinReyUO0mDXNQIDAQAB
    31  AoGAFiMyjqZevZ2R32jXgo+p5aR9HqU1K1igrG/HUFvJjeg1z4705cN5RXTLyozm
    32  UBvMG0bnbA+Nr9EhzvNrTwmUJ5H/7cXHEs0wOVO6y86bYO8XtP6Dfj2CvB704Zff
    33  mcjfROuGolt4PUODlJnZh71ZK4FXnBXfugfcSzj7Og8K1+ECQQD0+p6FEiICLM9l
    34  HrvZ85yFgZuRlzLo3AHuNIzpzhx4rRd1aijWhIGdlyg4hm0LJ0oCWK9YEJ0ce0yE
    35  W2vbmg69AkEAjCHtaGCK543eMWLSdDBy5O/Ye2oTi5uKWm32ezsnZBF3/oZibw7J
    36  kJBtYXx2Y+8MAeTzNE09GFe5lPtNZUHN2QJBAOAyECrGWntVGQR46P/g06jW4VGP
    37  Zxb2aYnfa+p5J1NFTYe1/OO9ZoWblUKNu3OOpEubb/UPV0l+iZtDs2TJC50CQD/Y
    38  WVUb301+aoRvtNjxFffOewBHpR4PQKrQvOMKYXkLKHOTgJd+0kEGPH+U+E+xovPd
    39  /xyOME698TS6hlmi8IkCQCfRNndp4oBTtxoZVETxWw/6zZzoRduR7Ut2Yo3VSckf
    40  rf7FI8Mzm5QV0eQOdwmHWKn1RRlJv+bOXBFttsrpgJo=
    41  -----END RSA PRIVATE KEY-----`)
    42  
    43  var publicKey = []byte(`-----BEGIN PUBLIC KEY-----
    44  MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCGGYYvHAZvjOVC6NtJNu42nwb1
    45  tvl1bhmgpwxg5gpnce0cuGK8N4kky86sOpuUDmRCCoXCyR8l5wEE+XOluf0NOIEg
    46  8cA0w1+je60bVztDCK/IAlI9szfdV7s0sFVgvb+SqoR6ADxmdPKnsIpqQfAYOSzw
    47  jMm/yinReyUO0mDXNQIDAQAB
    48  -----END PUBLIC KEY-----`)
    49  
    50  type mockedAuthenticator struct{}
    51  
    52  func (m *mockedAuthenticator) Validate(ctx context.Context, email, password string) (string, error) {
    53  	if email == "admin@example.com" && password == "password" {
    54  		return "id", nil
    55  	}
    56  
    57  	if email == "error" || password == "error" {
    58  		return "", fmt.Errorf("error")
    59  	}
    60  
    61  	return "", nil
    62  }
    63  
    64  type mockedAuthorizer struct{}
    65  
    66  func (m *mockedAuthorizer) Role(ctx context.Context, id string) (auth.Role, error) {
    67  	switch id {
    68  	case "admin":
    69  		return auth.RoleAdmin, nil
    70  	case "normal":
    71  		return auth.RoleNormal, nil
    72  	case "error":
    73  		return auth.RoleNormal, fmt.Errorf("error")
    74  	default:
    75  		return "", nil
    76  	}
    77  }
    78  
    79  func TestAuthService(t *testing.T) {
    80  	authService, err := auth.NewService(&mockedAuthenticator{}, &mockedAuthorizer{}, privateKey, publicKey, time.UTC)
    81  	if err != nil {
    82  		t.Fatalf("expected auth.NewService to succeed. got %s", err)
    83  	}
    84  
    85  	t.Run("invalid private/public keys", func(tt *testing.T) {
    86  		_, err := auth.NewService(&mockedAuthenticator{}, &mockedAuthorizer{}, []byte(""), []byte(""), time.UTC)
    87  		if err == nil {
    88  			tt.Fatal("expected auth.NewService to return an error")
    89  		}
    90  	})
    91  
    92  	t.Run("login/authentication with invalid credentials", func(tt *testing.T) {
    93  		token, err := authService.Login(context.Background(), "foo", "bar")
    94  		if err != auth.ErrInvalidCredentials {
    95  			tt.Fatal("expected Login to return an err")
    96  		}
    97  		if token != "" {
    98  			tt.Fatal("expected token to be empty")
    99  		}
   100  
   101  		id, err := authService.Authenticate(token)
   102  		if err != nil {
   103  			tt.Fatalf("expected Authenticate not return an error. got %s", err)
   104  		}
   105  		if id != "" {
   106  			tt.Fatal("expected token to not be authenticated")
   107  		}
   108  	})
   109  
   110  	t.Run("login with valid credentials", func(tt *testing.T) {
   111  		token, err := authService.Login(context.Background(), "admin@example.com", "password")
   112  		if err != nil {
   113  			tt.Fatalf("expected Login not return an error. got %s", err)
   114  		}
   115  		if token == "" {
   116  			tt.Fatal("expected token to not be empty")
   117  		}
   118  
   119  		id, err := authService.Authenticate(token)
   120  		if err != nil {
   121  			tt.Fatalf("expected Authenticate not return an error. got %s", err)
   122  		}
   123  		if id == "" {
   124  			tt.Fatal("expected token to be authenticated")
   125  		}
   126  	})
   127  
   128  	t.Run("Authorize calls authorizer", func(tt *testing.T) {
   129  		role, err := authService.Authorize(context.Background(), "admin")
   130  		if err != nil {
   131  			tt.Fatalf("expected Authorize not return an error. got %s", err)
   132  		}
   133  		if role != auth.RoleAdmin {
   134  			tt.Fatalf("expected role to be 'admin'. got %s", role)
   135  		}
   136  	})
   137  }