Skip to content

Commit

Permalink
decouple auth service from bos service
Browse files Browse the repository at this point in the history
  • Loading branch information
mk6i committed Jun 2, 2024
1 parent 7dc2057 commit 77bf07d
Show file tree
Hide file tree
Showing 32 changed files with 701 additions and 844 deletions.
8 changes: 7 additions & 1 deletion .mockery.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ packages:
OnlineNotifier:
config:
filename: "mock_online_notifier_test.go"
CookieCracker:
config:
filename: "mock_cookie_cracker_test.go"
github.com/mk6i/retro-aim-server/server/http:
interfaces:
UserManager:
Expand Down Expand Up @@ -97,4 +100,7 @@ packages:
filename: "mock_bart_manager_test.go"
LegacyBuddyListManager:
config:
filename: "mock_legacy_buddy_list_manager_test.go"
filename: "mock_legacy_buddy_list_manager_test.go"
CookieIssuer:
config:
filename: "mock_cookie_issuer_test.go"
45 changes: 31 additions & 14 deletions cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"fmt"
"log/slog"
"net"
"os"
"sync"

Expand Down Expand Up @@ -31,6 +32,12 @@ func main() {
os.Exit(1)
}

cookieBaker, err := state.NewHMACCookieBaker()
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "unable to create HMAC cookie baker: %s\n", err.Error())
os.Exit(1)
}

logger := middleware.NewLogger(cfg)
sessionManager := state.NewInMemorySessionManager(logger)
chatRegistry := state.NewChatRegistry()
Expand All @@ -45,10 +52,10 @@ func main() {
}()
go func(logger *slog.Logger) {
logger = logger.With("svc", "BOS")
authService := foodgroup.NewAuthService(cfg, sessionManager, sessionManager, feedbagStore, feedbagStore, chatRegistry, adjListBuddyListStore)
authService := foodgroup.NewAuthService(cfg, sessionManager, sessionManager, feedbagStore, feedbagStore, chatRegistry, adjListBuddyListStore, cookieBaker)
bartService := foodgroup.NewBARTService(logger, feedbagStore, sessionManager, feedbagStore, adjListBuddyListStore)
buddyService := foodgroup.NewBuddyService(sessionManager, feedbagStore, adjListBuddyListStore)
oServiceService := foodgroup.NewOServiceService(cfg, sessionManager, feedbagStore, adjListBuddyListStore, logger)
oServiceService := foodgroup.NewOServiceService(cfg, sessionManager, feedbagStore, adjListBuddyListStore, logger, cookieBaker)
oServiceServiceForBOS := foodgroup.NewOServiceServiceForBOS(*oServiceService, chatRegistry)
locateService := foodgroup.NewLocateService(sessionManager, feedbagStore, feedbagStore, adjListBuddyListStore)
newChatSessMgr := func() foodgroup.SessionManager { return state.NewInMemorySessionManager(logger) }
Expand All @@ -71,15 +78,17 @@ func main() {
OServiceBOSHandler: handler.NewOServiceHandlerForBOS(logger, oServiceService, oServiceServiceForBOS),
PermitDenyHandler: handler.NewPermitDenyHandler(logger, foodgroupService),
}),
CookieCracker: cookieBaker,
Logger: logger,
OnlineNotifier: oServiceServiceForBOS,
ListenAddr: net.JoinHostPort("", cfg.BOSPort),
}.Start()
wg.Done()
}(logger)
go func(logger *slog.Logger) {
logger = logger.With("svc", "CHAT")
authService := foodgroup.NewAuthService(cfg, sessionManager, sessionManager, feedbagStore, feedbagStore, chatRegistry, adjListBuddyListStore)
oServiceService := foodgroup.NewOServiceService(cfg, sessionManager, feedbagStore, adjListBuddyListStore, logger)
authService := foodgroup.NewAuthService(cfg, sessionManager, sessionManager, feedbagStore, feedbagStore, chatRegistry, adjListBuddyListStore, cookieBaker)
oServiceService := foodgroup.NewOServiceService(cfg, sessionManager, feedbagStore, adjListBuddyListStore, logger, cookieBaker)
chatService := foodgroup.NewChatService(chatRegistry)
oServiceServiceForChat := foodgroup.NewOServiceServiceForChat(*oServiceService, chatRegistry)

Expand All @@ -92,18 +101,20 @@ func main() {
}),
Logger: logger,
OnlineNotifier: oServiceServiceForChat,
CookieCracker: cookieBaker,
}.Start()
wg.Done()
}(logger)
go func(logger *slog.Logger) {
logger = logger.With("svc", "CHAT_NAV")
authService := foodgroup.NewAuthService(cfg, sessionManager, sessionManager, feedbagStore, feedbagStore, chatRegistry, adjListBuddyListStore)
oServiceService := foodgroup.NewOServiceService(cfg, sessionManager, feedbagStore, adjListBuddyListStore, logger)
sessionManager := state.NewInMemorySessionManager(logger)
authService := foodgroup.NewAuthService(cfg, sessionManager, sessionManager, feedbagStore, feedbagStore, chatRegistry, adjListBuddyListStore, cookieBaker)
oServiceService := foodgroup.NewOServiceService(cfg, sessionManager, feedbagStore, adjListBuddyListStore, logger, cookieBaker)
oServiceServiceForChatNav := foodgroup.NewOServiceServiceForChatNav(*oServiceService, chatRegistry)
newChatSessMgr := func() foodgroup.SessionManager { return state.NewInMemorySessionManager(logger) }
chatNavService := foodgroup.NewChatNavService(logger, chatRegistry, state.NewChatRoom, newChatSessMgr)

oscar.ChatNavServer{
oscar.BOSServer{
AuthService: authService,
Config: cfg,
Handler: handler.NewChatNavRouter(handler.Handlers{
Expand All @@ -112,35 +123,41 @@ func main() {
}),
Logger: logger,
OnlineNotifier: oServiceServiceForChatNav,
ListenAddr: net.JoinHostPort("", cfg.ChatNavPort),
CookieCracker: cookieBaker,
}.Start()
wg.Done()
}(logger)
go func(logger *slog.Logger) {
logger = logger.With("svc", "ALERT")
authService := foodgroup.NewAuthService(cfg, sessionManager, sessionManager, feedbagStore, feedbagStore, chatRegistry, adjListBuddyListStore)
oServiceService := foodgroup.NewOServiceService(cfg, sessionManager, feedbagStore, adjListBuddyListStore, logger)
sessionManager := state.NewInMemorySessionManager(logger)
authService := foodgroup.NewAuthService(cfg, sessionManager, sessionManager, feedbagStore, feedbagStore, chatRegistry, adjListBuddyListStore, cookieBaker)
oServiceService := foodgroup.NewOServiceService(cfg, sessionManager, feedbagStore, adjListBuddyListStore, logger, cookieBaker)
oServiceServiceForAlert := foodgroup.NewOServiceServiceForAlert(*oServiceService)

oscar.AlertServer{
oscar.BOSServer{
AuthService: authService,
Config: cfg,
Handler: handler.NewAlertRouter(handler.Handlers{
AlertHandler: handler.NewAlertHandler(logger),
OServiceAlertHandler: handler.NewOServiceHandlerForAlert(logger, oServiceService, oServiceServiceForAlert),
}),
CookieCracker: cookieBaker,
Logger: logger,
OnlineNotifier: oServiceServiceForAlert,
ListenAddr: net.JoinHostPort("", cfg.AlertPort),
}.Start()
wg.Done()
}(logger)
go func(logger *slog.Logger) {
logger = logger.With("svc", "AUTH")
authHandler := foodgroup.NewAuthService(cfg, sessionManager, nil, feedbagStore, feedbagStore, chatRegistry, adjListBuddyListStore)
authHandler := foodgroup.NewAuthService(cfg, sessionManager, nil, feedbagStore, feedbagStore, chatRegistry, adjListBuddyListStore, cookieBaker)

oscar.AuthServer{
AuthService: authHandler,
Config: cfg,
Logger: logger,
AuthService: authHandler,
Config: cfg,
Logger: logger,
CookieCracker: cookieBaker,
}.Start()
wg.Done()
}(logger)
Expand Down
2 changes: 1 addition & 1 deletion config/settings.env
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export FAIL_FAST=false

# Set logging granularity. Possible values: 'trace', 'debug', 'info', 'warn',
# 'error'.
export LOG_LEVEL=info
export LOG_LEVEL=debug

# The hostname that AIM clients connect to in order to reach OSCAR services
# (auth, BOS, BUCP, etc). Make sure the hostname is reachable by all clients.
Expand Down
55 changes: 21 additions & 34 deletions foodgroup/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,16 @@ import (
"github.com/google/uuid"
)

// authCookieLen is the fixed auth cookie length.
const authCookieLen = 256

// NewAuthService creates a new instance of AuthService.
func NewAuthService(cfg config.Config,
func NewAuthService(
cfg config.Config,
sessionManager SessionManager,
messageRelayer MessageRelayer,
feedbagManager FeedbagManager,
userManager UserManager,
chatRegistry ChatRegistry,
legacyBuddyListManager LegacyBuddyListManager,
cookieIssuer CookieIssuer,
) *AuthService {
return &AuthService{
chatRegistry: chatRegistry,
Expand All @@ -34,6 +33,7 @@ func NewAuthService(cfg config.Config,
messageRelayer: messageRelayer,
sessionManager: sessionManager,
userManager: userManager,
cookieIssuer: cookieIssuer,
}
}

Expand All @@ -48,26 +48,27 @@ type AuthService struct {
messageRelayer MessageRelayer
sessionManager SessionManager
userManager UserManager
cookieIssuer CookieIssuer
}

// RetrieveChatSession returns a chat room session. Return nil if the session
// does not exist.
func (s AuthService) RetrieveChatSession(loginCookie []byte) (*state.Session, error) {
// RegisterChatSession creates and returns a chat room session.
func (s AuthService) RegisterChatSession(loginCookie []byte) (*state.Session, error) {
c := chatLoginCookie{}
if err := wire.Unmarshal(&c, bytes.NewBuffer(loginCookie)); err != nil {
return nil, err
}
_, chatSessMgr, err := s.chatRegistry.Retrieve(c.Cookie)
room, chatSessMgr, err := s.chatRegistry.Retrieve(c.ChatCookie)
if err != nil {
return nil, err
}
return chatSessMgr.(SessionManager).RetrieveSession(c.SessID), nil
chatSess := chatSessMgr.(SessionManager).AddSession(c.ScreenName)
chatSess.SetChatRoomCookie(room.Cookie)
return chatSess, nil
}

// RetrieveBOSSession returns a user's session. Return nil if the session does
// not exist.
func (s AuthService) RetrieveBOSSession(sessionID string) (*state.Session, error) {
return s.sessionManager.RetrieveSession(sessionID), nil
// RegisterBOSSession creates and returns a user's session.
func (s AuthService) RegisterBOSSession(sessionID string) (*state.Session, error) {
return s.sessionManager.AddSession(sessionID), nil
}

// Signout removes this user's session and notifies users who have this user on
Expand Down Expand Up @@ -167,11 +168,10 @@ func (s AuthService) BUCPChallenge(
// (wire.LoginTLVTagsErrorSubcode).
func (s AuthService) BUCPLogin(
bodyIn wire.SNAC_0x17_0x02_BUCPLoginRequest,
newUUIDFn func() uuid.UUID,
newUserFn func(screenName string) (state.User, error),
) (wire.SNACMessage, error) {

block, err := s.login(bodyIn.TLVList, newUserFn, newUUIDFn)
block, err := s.login(bodyIn.TLVList, newUserFn)
if err != nil {
return wire.SNACMessage{}, err
}
Expand All @@ -197,20 +197,15 @@ func (s AuthService) BUCPLogin(
// (wire.LoginTLVTagsReconnectHere) and an authorization cookie
// (wire.LoginTLVTagsAuthorizationCookie). Else, an error code is set
// (wire.LoginTLVTagsErrorSubcode).
func (s AuthService) FLAPLogin(
frame wire.FLAPSignonFrame,
newUUIDFn func() uuid.UUID,
newUserFn func(screenName string) (state.User, error),
) (wire.TLVRestBlock, error) {
return s.login(frame.TLVList, newUserFn, newUUIDFn)
func (s AuthService) FLAPLogin(frame wire.FLAPSignonFrame, newUserFn func(screenName string) (state.User, error)) (wire.TLVRestBlock, error) {
return s.login(frame.TLVList, newUserFn)
}

// login validates a user's credentials and creates their session. it returns
// metadata used in both BUCP and FLAP authentication responses.
func (s AuthService) login(
TLVList wire.TLVList,
newUserFn func(screenName string) (state.User, error),
newUUIDFn func() uuid.UUID,
) (wire.TLVRestBlock, error) {

screenName, found := TLVList.String(wire.LoginTLVTagsScreenName)
Expand Down Expand Up @@ -249,24 +244,16 @@ func (s AuthService) login(
}
}

sess := s.sessionManager.AddSession(newUUIDFn().String(), screenName)

// Some clients (such as perl NET::OSCAR) expect the auth cookie to be
// exactly 256 bytes, even though the cookie is stored in a
// variable-length TLV. Pad the auth cookie to make sure it's exactly
// 256 bytes.
if len(sess.ID()) > authCookieLen {
return wire.TLVRestBlock{}, fmt.Errorf("sess is too long, expect 256 bytes, got %d", len(sess.ID()))
cookie, err := s.cookieIssuer.Issue([]byte(screenName))
if err != nil {
return wire.TLVRestBlock{}, fmt.Errorf("failed to make auth cookie: %w", err)
}
authCookie := make([]byte, authCookieLen)
copy(authCookie, sess.ID())

// auth success
return wire.TLVRestBlock{
TLVList: []wire.TLV{
wire.NewTLV(wire.LoginTLVTagsScreenName, screenName),
wire.NewTLV(wire.LoginTLVTagsReconnectHere, net.JoinHostPort(s.config.OSCARHost, s.config.BOSPort)),
wire.NewTLV(wire.LoginTLVTagsAuthorizationCookie, authCookie),
wire.NewTLV(wire.LoginTLVTagsAuthorizationCookie, cookie),
},
}, nil
}
Expand Down
Loading

0 comments on commit 77bf07d

Please sign in to comment.