From 3248a38549751ff6386caa5f0819c4b5c714d9c1 Mon Sep 17 00:00:00 2001 From: Michael-u21546551 Date: Tue, 9 Jul 2024 20:43:04 +0200 Subject: [PATCH 01/20] bash scripts to scan repo --- scripts/.gitignore | 1 - scripts/discover-large-repo-files.sh | 33 ++++++++++++++++++++++++++++ scripts/pull-remote-branches.sh | 4 ++++ 3 files changed, 37 insertions(+), 1 deletion(-) delete mode 100644 scripts/.gitignore create mode 100644 scripts/discover-large-repo-files.sh create mode 100644 scripts/pull-remote-branches.sh diff --git a/scripts/.gitignore b/scripts/.gitignore deleted file mode 100644 index cd0d0072..00000000 --- a/scripts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.sh \ No newline at end of file diff --git a/scripts/discover-large-repo-files.sh b/scripts/discover-large-repo-files.sh new file mode 100644 index 00000000..7be2716d --- /dev/null +++ b/scripts/discover-large-repo-files.sh @@ -0,0 +1,33 @@ +#!/bin/bash +#set -x + +# Shows you the largest objects in your repo's pack file. +# Written for osx. +# +# @see http://stubbisms.wordpress.com/2009/07/10/git-script-to-show-largest-pack-objects-and-trim-your-waist-line/ +# @author Antony Stubbs + +# set the internal field spereator to line break, so that we can iterate easily over the verify-pack output +IFS=$'\n'; + +# list all objects including their size, sort by size, take top 10 +objects=`git verify-pack -v /mnt/c/Users/bbdnet3218/Documents/GitHub/occupi/.git/objects/pack/pack-*.idx | grep -v chain | sort -k3nr | head -n 60` + +echo "All sizes are in kB. The pack column is the size of the object, compressed, inside the pack file." + +output="size,pack,SHA,location" +for y in $objects +do + # extract the size in bytes + size=$((`echo $y | cut -f 5 -d ' '`/1024)) + # extract the compressed size in bytes + compressedSize=$((`echo $y | cut -f 6 -d ' '`/1024)) + # extract the SHA + sha=`echo $y | cut -f 1 -d ' '` + # find the objects location in the repository tree + other=`git rev-list --all --objects | grep $sha` + #lineBreak=`echo -e "\n"` + output="${output}\n${size},${compressedSize},${other}" +done + +echo -e $output | column -t -s ', ' \ No newline at end of file diff --git a/scripts/pull-remote-branches.sh b/scripts/pull-remote-branches.sh new file mode 100644 index 00000000..4f3fd576 --- /dev/null +++ b/scripts/pull-remote-branches.sh @@ -0,0 +1,4 @@ +#!/bin/bash +for branch in `git branch -a | grep remotes | grep -v HEAD | grep -v master`; do + git branch --track ${branch##*/} $branch +done \ No newline at end of file From 082a0c2bb305026e5ff8e501d979140d1dd37ebe Mon Sep 17 00:00:00 2001 From: Michael-u21546551 Date: Wed, 31 Jul 2024 22:02:32 +0200 Subject: [PATCH 02/20] basic: added webauthn config --- occupi-backend/configs/setup.go | 29 +++++++++++++++++++++++++++++ occupi-backend/go.mod | 9 +++++---- occupi-backend/go.sum | 6 ++++++ 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/occupi-backend/configs/setup.go b/occupi-backend/configs/setup.go index ce5dcc6c..970906c4 100644 --- a/occupi-backend/configs/setup.go +++ b/occupi-backend/configs/setup.go @@ -5,6 +5,7 @@ import ( "time" "github.com/allegro/bigcache/v3" + "github.com/go-webauthn/webauthn/webauthn" "github.com/ipinfo/go/v2/ipinfo" "github.com/ipinfo/go/v2/ipinfo/cache" @@ -187,3 +188,31 @@ func CreateRabbitQueue(ch *amqp.Channel) amqp.Queue { return q } + +func CreateWebAuthnInstance() *webauthn.WebAuthn { + // WebAuthn parameters + rpID := GetRPID() + rpName := GetRPName() + rpOrigin := GetRPOrigin() + rpIcon := GetRPIcon() + rpChallengeLength := GetRPChallengeLength() + rpTimeout := GetRPTimeout() + rpIDLength := GetRPIDLength() + + // Create a new WebAuthn instance + webAuthn := webauthn.New(&webauthn.Config{ + RPID: rpID, + RPName: rpName, + RPOrigin: rpOrigin, + RPIcon: rpIcon, + RPChallengeLength: rpChallengeLength, + RPTimeout: rpTimeout, + RPIDLength: rpIDLength, + Attestation: webauthn.ConveyAttestationNone, + AuthenticatorSelection: webauthn.AuthenticatorSelection{ + UserVerification: webauthn.VerificationRequired, + }, + }) + + return webAuthn +} diff --git a/occupi-backend/go.mod b/occupi-backend/go.mod index 81ebe3e7..1a53e455 100644 --- a/occupi-backend/go.mod +++ b/occupi-backend/go.mod @@ -1,8 +1,8 @@ module github.com/COS301-SE-2024/occupi/occupi-backend -go 1.21 +go 1.22 -toolchain go1.21.6 +toolchain go1.22.5 require ( github.com/alexedwards/argon2id v1.0.0 @@ -24,6 +24,7 @@ require ( ) require ( + github.com/go-webauthn/webauthn v0.11.0 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect @@ -84,11 +85,11 @@ require ( go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect golang.org/x/arch v0.8.0 // indirect - golang.org/x/crypto v0.24.0 // indirect + golang.org/x/crypto v0.25.0 // indirect golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect golang.org/x/net v0.26.0 // indirect golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.21.0 // indirect + golang.org/x/sys v0.22.0 // indirect golang.org/x/text v0.16.0 // indirect google.golang.org/protobuf v1.34.1 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect diff --git a/occupi-backend/go.sum b/occupi-backend/go.sum index 751a36b3..31cfa935 100644 --- a/occupi-backend/go.sum +++ b/occupi-backend/go.sum @@ -42,6 +42,8 @@ github.com/go-playground/validator v9.31.0+incompatible h1:UA72EPEogEnq76ehGdEDp github.com/go-playground/validator v9.31.0+incompatible/go.mod h1:yrEkQXlcI+PugkyDjY2bRrL/UBU4f3rvrgkN3V8JEig= github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8= github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-webauthn/webauthn v0.11.0 h1:2U0jWuGeoiI+XSZkHPFRtwaYtqmMUsqABtlfSq1rODo= +github.com/go-webauthn/webauthn v0.11.0/go.mod h1:57ZrqsZzD/eboQDVtBkvTdfqFYAh/7IwzdPT+sPWqB0= github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= @@ -177,6 +179,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -208,6 +212,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= From e5d17d6eaafeeccf28484db082ae3d61bb7e4229 Mon Sep 17 00:00:00 2001 From: Michael-u21546551 Date: Thu, 1 Aug 2024 10:08:44 +0200 Subject: [PATCH 03/20] chore: Add BeginLoginAdmin and FinishLoginAdmin functions in auth_handlers.go for begginign webauthn integration --- occupi-backend/configs/config.go | 28 +++++++++++++++ occupi-backend/configs/config.yaml.gpg | Bin 383 -> 393 bytes occupi-backend/configs/dev.deployed.yaml.gpg | Bin 959 -> 981 bytes occupi-backend/configs/dev.localhost.yaml.gpg | Bin 909 -> 928 bytes occupi-backend/configs/prod.yaml.gpg | Bin 947 -> 971 bytes occupi-backend/configs/setup.go | 34 +++++++++--------- occupi-backend/configs/test.yaml.gpg | Bin 857 -> 866 bytes occupi-backend/go.mod | 12 +++++-- occupi-backend/go.sum | 18 +++++++--- occupi-backend/pkg/handlers/auth_handlers.go | 6 ++++ occupi-backend/pkg/models/app.go | 3 ++ 11 files changed, 76 insertions(+), 25 deletions(-) diff --git a/occupi-backend/configs/config.go b/occupi-backend/configs/config.go index 445b14e5..33d1bb36 100644 --- a/occupi-backend/configs/config.go +++ b/occupi-backend/configs/config.go @@ -44,6 +44,9 @@ const ( RabbitMQPassword = "RABBITMQ_PASSWORD" RabbitMQHost = "RABBITMQ_HOST" RabbitMQPort = "RABBITMQ_PORT" + RPID = "RP_ID" + RPName = "RP_NAME" + RPOrigins = "RP_ORIGINS" ) // init viper @@ -378,3 +381,28 @@ func GetRabbitMQPort() string { } return port } + +func GetRPID() string { + id := viper.GetString(RPID) + if id == "" { + id = "RP_ID" + } + return id +} + +func GetRPName() string { + name := viper.GetString(RPName) + if name == "" { + name = "RP_NAME" + } + return name +} + +func GetRPOrigins() []string { + origins := viper.GetString(RPOrigins) + if origins != "" { + originList := strings.Split(origins, ",") + return originList + } + return []string{} +} diff --git a/occupi-backend/configs/config.yaml.gpg b/occupi-backend/configs/config.yaml.gpg index de6683689ed7e1e6b90c4f065bf4e93d99014209..6ffd414dd1dc63cb77e887977f39f67b2fc562bc 100644 GIT binary patch literal 393 zcmV;40e1e34Fm}T0^u(osEZUfBFs?Ltb7Ym*D*6#o!lLB!k9AH}-5c+P6wy1l>^4ai z$P%zMSl>k?S>TA?8!-2T`jJswx_NkoMy`0K81tGlHn5618v(-TL(P+8wW_ovU}S}2 z5!{y@O!1_Zy?K*%6%cgFTWt1{80`X#M+-|qkCpXlXx!5lQWZP&BjUdG_`|Z*WoR%6 z$zv@tIm>5QO;^gm$}JfWN|}29H^Khb=2Q;EmW~?fHi(>4!=5oD$3UM_qUePEbAGip z&dTOKe5ENKIFo0B{t~Nw_ajVf8fyhm=8fzn$}_)V&psS`1E z)$Pr|!?EbBHz89b2ys_L2m!p3g1mk*+(f5al#2dsZ literal 383 zcmV-_0f7FD4Fm}T0_-@w^UGd?uK&`&tpVu#z!j|ttxC+412~=8;K#z@=Gbkyrf#9N zFmiUm^V`3aW@E*-dp&YzJ*9YgQS^0GvG{tM6C(C+rX zFcK{)gye?UB!#kQcBBJ8trE)lK*0bU4lII6av7Y~9-7@HNvxYli!#Hk9G0nIM{?&V1Ap;re`bm@%yM%ti3oO=bscc`lk18` z5d1{W+X?^Wi^7g($zs1~R&af66u~djq(@9qdEWeau4M}0cKda;Sw>;atkzMhaU3dV zS_UjyYn-JP^c*lXy(}LkI`gS>F9fuE$)@!K{zHGg-qqoRT&+LQ(rx!Mwju9b5pV*` z4u1Z_4#=HsUj-_l8Lmcx85%vN1Y+fX2IG-M1>2(?UX6AFuOYNee=keWS(K`gZ`2i_ zaOmtMUZ-VRHQX~LKwr+VjTT+!#e|Iv^sTI*sMQB;O~dEL#96xG9nQE?*&k=|0CBPO zhGAM}S2%COt53%-;|N5!-azybA=U%g-<*u+0fJQLya31JGNPYH17wsVRa5iIk|R?A zT}b3+7E`5^2=42|Jw4rPwv9|hbv1W8wU;Z0E0L@UX1V$`bMUJ;xuX2bfFr(CW%yNw z^mN5R8Wy+=j80u`WSwO1sWis@)1*(UPU4t?_ydX(N{;ccZvwG@-3}4s{;$fNv8nZu zBmK9qS(^F7jan*mIG3hFNcBMM{VSUZQd0&0GRfO1fZ&nfccGfO_mp!X+RgYn?(q#k Dwz1=@ literal 959 zcmV;w13>(Y4Fm}T0{@mGS5-wRe*e%;0!uboUk@#^HUe=m&Yy<9z62r@o^aHTCIQ5$pnEWAU*{vA z&;h?VYdQd2Q7Zpyr;Xo(JE2EDF1JumRmwMjD&EHmcgrXHc*8V3Jy?%MqXdW)PTUKl zn&|PGm#qaR0t7D9{)J3*EG*9quK-kKo^o^3N7rvASVk|KMPWOFIphynCFd(ec4K2b zIgeOyzull;*2Jl{yS~qZ0wF{m4F95wyqh5lg62Z#R#0Dg+-9>B`Nza3g+6LKkg^KX zl#~h7j{O~BOir+O062)X+aC>{#W3}LFp2PX_n1EIxSp&p^{gc|?Cn8+_NViBxLBG6 zb=gyXCnci&zg6PTa!0zNxF3*wwr;(dX5(Cql&VoHpN=JtG&9z_KFJWV{`YnU7gzW^ zpWQ~`?j4nO=l|x3E0k94E>6WQSH@yhL11C(Y*=wQuU3dNmu7K>R^g1C4-iuU`(6&{ z`G=Az4sJ_rsvJWJsQ8zk%evb_=ZEi1&_tiNxXkOVuY6QqW@XX0;410wdACQElMg;s z2}385Z4Db%-ely6fa4o@!0a|~>OG;J`Nh=ThAbD2?llZG5azJU#M}V7Av$x=*Htkq zowRPw@gEpoou>{c5w+z1)3m^KccafW#k%Fywe~fn(+e#fCljw1>$Z8C?}k+a6Gh-# z=Fz~8Anaa8GcW@*>E!`WX4VQYl{KT}{;Y4E0!!6L_li=Za@J{(vMZ|V*H@? zp99F_u|PX#6q)pt1jq$cKxtAiTrL2+)f467os!KtFzo|T<81gsFZL5b7hkq0h5k+T))Dlv8I%C=9kB<}8yG19kwp@58IX0P>CS?X&D|monD8S{=*W;X*IfVr diff --git a/occupi-backend/configs/dev.localhost.yaml.gpg b/occupi-backend/configs/dev.localhost.yaml.gpg index b7823acb2b524932459af5f072108ff22add6046..bc1cfc110da5d5f4b7e50141259e30c61c856f43 100644 GIT binary patch literal 928 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 literal 947 zcmV;k15Esk4Fm}T0zI$!7(4~yja9QKQn) zh3Tjr-<)NW;y2@t#IYd8AxAtv`F;~irjhuIv!sNBu8M7O*{7;ww4H5*=#X$-v3J-- zV_07VsXP@&)*orj?uHw5V+6S#oQR!jNuH-LLe0pimecs*tul^f-j4wZnQQf4y- zEHItuF{g>-1k4GyGl(1}?Br_6Hn*e+h*VP!*|C_86phz4w$ z-;r1t{`f3x#!2GhqyT#ja&y5;Pd?4|BeqML`OTKp`rCBG4pm4AT2_|w+{T`2DxZ!W zu=8;CzIe@&n~4r~CvD2fT=p4()h%80xjjP|gtYmi3+A`~lt6g~Gw3ycL*!@d8}Y!f zVueG-^|MiS^n6Q42H z2scd=GPO<(R3T&>F(33TA~HCa%9H;SI)a7+Jwj)(pWat5P&+FYoo=blyT%Z3=1cuD z2Q#x{so*=34qpE#O#C2py)fMlvpTF%hH6Y{nWfKIuQ#>+)|4 z86%J}CQs_R_5Q5&3HVjF^}lz5vDhDq-%iozM0LmVuz_NIJ?Vf-O;6ZlzT3GJY&Kr_ zC~7bmv8ldJ$AJGxHgqdb?<}i|QfR0m_FftP5sK=KoN9W+Ll7T?NdS4#MGz7*m=16N zR9ns8Wb>X7VwWwfxctH7^nz?TW242L0*49t)nCYaxm?mMKR6b#dw9-!BmKeDf_#%zH|Sj6v%kHX+HBoqf2W@L)p(&c72) z!}KSdKnGniv(f4K7LS#LE#CO2v2f~v<40?QTof)r$~TQ%`4R5`iv6|pGM;C-ORbO#O??A!F5?f;3!0HLd!En%=@F#OT6{weNWFs%zuF_>` zA3HI5+de(wXBC+07;n3htEMNP&j2%*=mKAXcvyN_y{DnDVR6$nXg%^ygm|{Dqe?8@ z#NGE-6rY*HR5a{&UmgjEGilc;9d{{RU3ZE_!uZi9Urm7d+L{~WF0(fRH82fCcjKC%)o0$cM72=-A~9&gr! zntel*hMy&FQD1-zT4~y5PXjK*RZ{^VR~ZmE`F$)a7pJi}p2&;&Y3PhRJ5Dep7ySM~ zC&mM}&oXf3*aMJ2NU=c?ciQcov~@P+CaYkoT9?D=u_hQ%-_G2e9N2xdEt;`c+{|Z< zB}w2b+YnoeT5a9~3tw^8R>O$KY3CTTEMFW{kYJDi z+=d!BqAiPNWx)&`Rm|62BUj!C!jCD;#jy|hEyHbgib1sBU%UHCZZS*pz`RZ7#_P(< z1Jl#DB8iEK=*zjYb%M*Szq&v##!_v+BKL^Z()`8O0hFyjdF=@(L;+CdU>j&Y&Nv#= zJTmMm41N?C8N<#c5z1S0ZN!c8{x6#%_Djuqy48Ub%5jiN<5d+03G(P#rKQH07y89T zK%HFU;`?;R?psV3+8hYai!9p6IOeRzCFEBqud~rOE|A1Mdb4Nwu_G{1-JMcNo~)}< s!|NC=iD8TY%pOQ4$pE1tA^xI`Bwx!2Pl8xRNL>soH9A<7b7Mo_Y8?KbcmMzZ literal 857 zcmV-f1E&0p4Fm}T0;LC()ddE3e*e1uF831lMbb6wIHKeb*c8+slJc%7Y z8D2j#Fy7%yG2MUIN~Ck1L$vIba85FFOwqd8m0?YCWX%>d;T02r9X4ikd`UIOwj!=& z(J@SclIgr3JkX**yc|H6E^q9}pTO{D^bCqMfod5IpV*d&XbuD?tAVizOw1NWubFps zJXuj68bIl@7S_V135b}FLCZGXvYPr)0*^6gt5lrdAUfen+4mxC(Z60^-J^<0f|iyi zF*Gf=&}RLB;xVlWsyAfrz=jqM&K(;m%4GXe(EY6)03rxQTR(p=2qZC?%GFYo7=lY$ zW|E16E|R)nppeWyXTt9b;NX05h2|Rbi$ZpUpR?h)lVk5w?F$rI-d;t| z%F#w=*V;8N1Zj2_kh%Mg-ACXO!P%KYy5aY46kpl4K75*VD#ogqef15lHF*R3Ffq jX*s^noQ*Uc!5r7`Zp4@ Date: Thu, 1 Aug 2024 20:51:04 +0200 Subject: [PATCH 04/20] feat: Add session management for WebAuthn authentication --- occupi-backend/pkg/cache/cache.go | 56 ++++++++++ occupi-backend/pkg/cache/cache_keys_gen.go | 4 + occupi-backend/pkg/database/database.go | 63 ++++++++++- occupi-backend/pkg/handlers/auth_handlers.go | 108 ++++++++++++++++++- occupi-backend/pkg/handlers/auth_helpers.go | 33 ++++++ occupi-backend/pkg/models/app.go | 40 ++++++- occupi-backend/pkg/models/database.go | 8 +- 7 files changed, 303 insertions(+), 9 deletions(-) diff --git a/occupi-backend/pkg/cache/cache.go b/occupi-backend/pkg/cache/cache.go index bc407577..bd9e6e7d 100644 --- a/occupi-backend/pkg/cache/cache.go +++ b/occupi-backend/pkg/cache/cache.go @@ -4,6 +4,7 @@ import ( "errors" "github.com/COS301-SE-2024/occupi/occupi-backend/pkg/models" + "github.com/go-webauthn/webauthn/webauthn" "github.com/sirupsen/logrus" "go.mongodb.org/mongo-driver/bson" ) @@ -219,3 +220,58 @@ func DeleteImage(appsession *models.AppSession, id string) { return } } + +func SetSession(appsession *models.AppSession, session *webauthn.SessionData, email string) error { + if appsession.Cache == nil { + return errors.New("cache not found") + } + + // marshal the session + sessionData, err := bson.Marshal(session) + if err != nil { + logrus.Error("failed to marshall", err) + return err + } + + // set the session in the cache + if err := appsession.Cache.Set(SessionKey(email), sessionData); err != nil { + logrus.Error("failed to set session in cache", err) + return err + } + + return nil +} + +func GetSession(appsession *models.AppSession, email string) (*webauthn.SessionData, error) { + if appsession.Cache == nil { + return nil, errors.New("cache not found") + } + + // unmarshal the session from the cache + var session webauthn.SessionData + sessionData, err := appsession.Cache.Get(SessionKey(email)) + + if err != nil { + logrus.Error("key does not exist: ", err) + return nil, err + } + + if err := bson.Unmarshal(sessionData, &session); err != nil { + logrus.Error("failed to unmarshall", err) + return nil, err + } + + return &session, nil +} + +func DeleteSession(appsession *models.AppSession, email string) { + if appsession.Cache == nil { + return + } + + // delete the session from the cache + if err := appsession.Cache.Delete(SessionKey(email)); err != nil { + logrus.Error("failed to delete session from cache", err) + return + } +} diff --git a/occupi-backend/pkg/cache/cache_keys_gen.go b/occupi-backend/pkg/cache/cache_keys_gen.go index 7a22b2ab..af06d3de 100644 --- a/occupi-backend/pkg/cache/cache_keys_gen.go +++ b/occupi-backend/pkg/cache/cache_keys_gen.go @@ -15,3 +15,7 @@ func RoomBookingKey(roomID string) string { func ImageKey(imageID string) string { return "Images:" + imageID } + +func SessionKey(email string) string { + return "Sessions:" + email +} diff --git a/occupi-backend/pkg/database/database.go b/occupi-backend/pkg/database/database.go index 2c35a0c3..a06e894c 100644 --- a/occupi-backend/pkg/database/database.go +++ b/occupi-backend/pkg/database/database.go @@ -11,6 +11,7 @@ import ( "github.com/COS301-SE-2024/occupi/occupi-backend/pkg/constants" "github.com/COS301-SE-2024/occupi/occupi-backend/pkg/models" "github.com/COS301-SE-2024/occupi/occupi-backend/pkg/sender" + "github.com/go-webauthn/webauthn/webauthn" "github.com/ipinfo/go/v2/ipinfo" "github.com/sirupsen/logrus" "go.mongodb.org/mongo-driver/bson" @@ -1087,8 +1088,11 @@ func GetSecuritySettings(ctx *gin.Context, appsession *models.AppSession, email collection := appsession.DB.Database(configs.GetMongoDBName()).Collection("Users") filter := bson.M{"email": email} + findOptions := options.FindOne() + // exclude the security.credentials field only + findOptions.SetProjection(bson.M{"security.credentials": 0}) var user models.User - err := collection.FindOne(ctx, filter).Decode(&user) + err := collection.FindOne(ctx, filter, findOptions).Decode(&user) if err != nil { logrus.Error(err) return models.SecuritySettingsRequest{}, err @@ -1544,3 +1548,60 @@ func AddRoom(ctx *gin.Context, appsession *models.AppSession, rroom models.Reque return res.InsertedID.(primitive.ObjectID).Hex(), nil } + +func GetUserCredentials(ctx *gin.Context, appsession *models.AppSession, email string) (webauthn.Credential, error) { + // check if database is nil + if appsession.DB == nil { + logrus.Error("Database is nil") + return webauthn.Credential{}, errors.New("database is nil") + } + + // check if user is in cache + if userData, err := cache.GetUser(appsession, email); err == nil { + return userData.Security.Credentials, nil + } + + collection := appsession.DB.Database(configs.GetMongoDBName()).Collection("Users") + + filter := bson.M{"email": email} + var user models.User + err := collection.FindOne(ctx, filter).Decode(&user) + if err != nil { + return webauthn.Credential{}, err + } + + // Add the user to the cache if cache is not nil + cache.SetUser(appsession, user) + + return user.Security.Credentials, nil +} + +func AddUserCredential(ctx *gin.Context, appsession *models.AppSession, email string, credential *webauthn.Credential) error { + // check if database is nil + if appsession.DB == nil { + logrus.Error("Database is nil") + return errors.New("database is nil") + } + + // get user from cache + userData, cacheErr := cache.GetUser(appsession, email) + + collection := appsession.DB.Database(configs.GetMongoDBName()).Collection("Users") + + filter := bson.M{"email": email} + update := bson.M{"$set": bson.M{"security.credentials": credential}} + + _, err := collection.UpdateOne(ctx, filter, update) + if err != nil { + logrus.Error(err) + return err + } + + // update user in cache + if cacheErr == nil { + userData.Security.Credentials = *credential + cache.SetUser(appsession, userData) + } + + return nil +} diff --git a/occupi-backend/pkg/handlers/auth_handlers.go b/occupi-backend/pkg/handlers/auth_handlers.go index 6be0822c..04504bc1 100644 --- a/occupi-backend/pkg/handlers/auth_handlers.go +++ b/occupi-backend/pkg/handlers/auth_handlers.go @@ -4,18 +4,20 @@ import ( "net/http" "github.com/COS301-SE-2024/occupi/occupi-backend/configs" + "github.com/COS301-SE-2024/occupi/occupi-backend/pkg/cache" "github.com/COS301-SE-2024/occupi/occupi-backend/pkg/constants" "github.com/COS301-SE-2024/occupi/occupi-backend/pkg/database" "github.com/COS301-SE-2024/occupi/occupi-backend/pkg/mail" "github.com/COS301-SE-2024/occupi/occupi-backend/pkg/models" "github.com/COS301-SE-2024/occupi/occupi-backend/pkg/utils" + "github.com/go-webauthn/webauthn/webauthn" "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" ) // handler for logging a new user on occupi /auth/login -func Login(ctx *gin.Context, appsession *models.AppSession, role string, cookies bool) { +func Login(ctx *gin.Context, appsession *models.AppSession, role string, cookies bool, shouldWebAuthN bool) { var requestUser models.RequestUser if err := ctx.ShouldBindBodyWithJSON(&requestUser); err != nil { ctx.JSON(http.StatusBadRequest, utils.ErrorResponse( @@ -65,6 +67,14 @@ func Login(ctx *gin.Context, appsession *models.AppSession, role string, cookies return } + if shouldWebAuthN { + err := WebAuthNAuthentication(ctx, appsession, requestUser) + if err != nil { + logrus.WithError(err).Error("Error with WebAuthN authentication") + } + return + } + // generate a jwt token for the user token, expirationTime, err := GenerateJWTTokenAndStartSession(ctx, appsession, requestUser.Email, role) @@ -77,11 +87,103 @@ func Login(ctx *gin.Context, appsession *models.AppSession, role string, cookies AllocateAuthTokens(ctx, token, expirationTime, cookies) } -func BeginLoginAdmin(ctx *gin.Context, appsession *models.AppSession) { +func FinishLoginAdmin(ctx *gin.Context, appsession *models.AppSession, role string, cookies bool) { + var requestEmail models.RequestEmail + if err := ctx.ShouldBindBodyWithJSON(&requestEmail); err != nil { + ctx.JSON(http.StatusBadRequest, utils.ErrorResponse( + http.StatusBadRequest, + "Invalid request payload", + constants.InvalidRequestPayloadCode, + "Expected email field", + nil)) + return + } + + // fetch sessionData from the cache + sessionData, err := cache.GetSession(appsession, requestEmail.Email) + + if err != nil { + ctx.JSON(http.StatusInternalServerError, utils.InternalServerError()) + logrus.WithError(err).Error("Error fetching session data from cache") + return + } + // get the user's credentials from the database + cred, err := database.GetUserCredentials(ctx, appsession, requestEmail.Email) + + if err != nil { + ctx.JSON(http.StatusInternalServerError, utils.InternalServerError()) + logrus.WithError(err).Error("Error fetching user credentials from database") + return + } + + user := models.NewWebAuthnUser([]byte(requestEmail.Email), requestEmail.Email, requestEmail.Email, cred) + + credential, err := appsession.WebAuthn.FinishLogin(user, *sessionData, ctx.Request) + + if err != nil { + ctx.JSON(http.StatusInternalServerError, utils.InternalServerError()) + logrus.WithError(err).Error("Error finishing login") + return + } + + err = database.AddUserCredential(ctx, appsession, requestEmail.Email, credential) + + if err != nil { + ctx.JSON(http.StatusInternalServerError, utils.InternalServerError()) + logrus.WithError(err).Error("Error finishing login") + return + } + + // generate a jwt token for the user + token, expirationTime, err := GenerateJWTTokenAndStartSession(ctx, appsession, requestEmail.Email, role) + + if err != nil { + logrus.WithError(err).Error("Error generating JWT token") + return + } + + // Use AllocateAuthTokens to handle the response + AllocateAuthTokens(ctx, token, expirationTime, cookies) +} + +func BeginRegistrationAdmin(ctx *gin.Context, appsession *models.AppSession) { + var requestEmail models.RequestEmail + if err := ctx.ShouldBindBodyWithJSON(&requestEmail); err != nil { + ctx.JSON(http.StatusBadRequest, utils.ErrorResponse( + http.StatusBadRequest, + "Invalid request payload", + constants.InvalidRequestPayloadCode, + "Expected email field", + nil)) + return + } + + webauthnUser := models.NewWebAuthnUser([]byte(requestEmail.Email), requestEmail.Email, requestEmail.Email, webauthn.Credential{}) + options, sessionData, err := appsession.WebAuthn.BeginRegistration(webauthnUser) + if err != nil { + logrus.WithError(err).Error("Error beginning WebAuthn registration") + ctx.JSON(http.StatusInternalServerError, utils.InternalServerError()) + return + } + + // Save the session data - cache will expire in x defined minutes according to the config + if err := cache.SetSession(appsession, sessionData, requestEmail.Email); err != nil { + logrus.WithError(err).Error("Error saving session data in cache") + ctx.JSON(http.StatusInternalServerError, utils.InternalServerError()) + return + } + + ctx.JSON(http.StatusOK, utils.SuccessResponse( + http.StatusOK, + "WebAuthn login initiated", + gin.H{"options": options, "sessionData": sessionData}, + )) } -func FinishLoginAdmin(ctx *gin.Context, appsession *models.AppSession) {} +func FinishRegistrationAdmin(ctx *gin.Context, appsession *models.AppSession) { + +} // handler for registering a new user on occupi /auth/register func Register(ctx *gin.Context, appsession *models.AppSession) { diff --git a/occupi-backend/pkg/handlers/auth_helpers.go b/occupi-backend/pkg/handlers/auth_helpers.go index 9a490a44..a0754911 100644 --- a/occupi-backend/pkg/handlers/auth_helpers.go +++ b/occupi-backend/pkg/handlers/auth_helpers.go @@ -1,11 +1,13 @@ package handlers import ( + "fmt" "net/http" "time" "github.com/COS301-SE-2024/occupi/occupi-backend/configs" "github.com/COS301-SE-2024/occupi/occupi-backend/pkg/authenticator" + "github.com/COS301-SE-2024/occupi/occupi-backend/pkg/cache" "github.com/COS301-SE-2024/occupi/occupi-backend/pkg/constants" "github.com/COS301-SE-2024/occupi/occupi-backend/pkg/database" "github.com/COS301-SE-2024/occupi/occupi-backend/pkg/mail" @@ -545,3 +547,34 @@ func AttemptToSignNewEmail(ctx *gin.Context, appsession *models.AppSession, emai )) } } + +func WebAuthNAuthentication(ctx *gin.Context, appsession *models.AppSession, requestUser models.RequestUser) error { + // Begin WebAuthn login process + cred, err := database.GetUserCredentials(ctx, appsession, requestUser.Email) + if err != nil { + ctx.JSON(http.StatusOK, utils.SuccessResponse( + http.StatusOK, + "Error getting user credentials, please register for WebAuthn", + gin.H{"error": "Error getting user credentials, please register for WebAuthn"})) + return fmt.Errorf("error getting user credentials: %v", err) + } + webauthnUser := models.NewWebAuthnUser([]byte(requestUser.Email), requestUser.Email, requestUser.Email, cred) + options, sessionData, err := appsession.WebAuthn.BeginLogin(webauthnUser) + if err != nil { + ctx.JSON(http.StatusInternalServerError, utils.InternalServerError()) + return fmt.Errorf("error beginning WebAuthn login: %v", err) + } + + // Save the session data - cache will expire in x defined minutes according to the config + if err := cache.SetSession(appsession, sessionData, requestUser.Email); err != nil { + ctx.JSON(http.StatusInternalServerError, utils.InternalServerError()) + return fmt.Errorf("error saving WebAuthn session data: %v", err) + } + + ctx.JSON(http.StatusOK, utils.SuccessResponse( + http.StatusOK, + "WebAuthn login initiated", + gin.H{"options": options, "sessionData": sessionData}, + )) + return nil +} diff --git a/occupi-backend/pkg/models/app.go b/occupi-backend/pkg/models/app.go index ff64bce9..879c6c76 100644 --- a/occupi-backend/pkg/models/app.go +++ b/occupi-backend/pkg/models/app.go @@ -23,7 +23,7 @@ type AppSession struct { RabbitMQ *amqp.Connection RabbitCh *amqp.Channel RabbitQ amqp.Queue - webAuthn *webauthn.WebAuthn + WebAuthn *webauthn.WebAuthn } // constructor for app session @@ -41,6 +41,42 @@ func New(db *mongo.Client, cache *bigcache.BigCache) *AppSession { RabbitMQ: conn, RabbitCh: ch, RabbitQ: q, - webAuthn: configs.CreateWebAuthnInstance(), + WebAuthn: configs.CreateWebAuthnInstance(), + } +} + +type WebAuthnUser struct { + ID []byte + Name string + DisplayName string + Credentials []webauthn.Credential +} + +// WebAuthnCredentials implements webauthn.User. +func (u WebAuthnUser) WebAuthnCredentials() []webauthn.Credential { + return u.Credentials +} + +// WebAuthnDisplayName implements webauthn.User. +func (u WebAuthnUser) WebAuthnDisplayName() string { + return u.DisplayName +} + +// WebAuthnID implements webauthn.User. +func (u WebAuthnUser) WebAuthnID() []byte { + return u.ID +} + +// WebAuthnName implements webauthn.User. +func (u WebAuthnUser) WebAuthnName() string { + return u.Name +} + +func NewWebAuthnUser(id []byte, name, displayName string, credentials webauthn.Credential) WebAuthnUser { + return WebAuthnUser{ + ID: id, + Name: name, + DisplayName: displayName, + Credentials: []webauthn.Credential{credentials}, } } diff --git a/occupi-backend/pkg/models/database.go b/occupi-backend/pkg/models/database.go index b7b87759..866a490d 100644 --- a/occupi-backend/pkg/models/database.go +++ b/occupi-backend/pkg/models/database.go @@ -3,6 +3,7 @@ package models import ( "time" + "github.com/go-webauthn/webauthn/webauthn" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) @@ -66,9 +67,10 @@ type Notifications struct { } type Security struct { - MFA bool `json:"mfa" bson:"mfa"` - Biometrics bool `json:"biometrics" bson:"biometrics"` - ForceLogout bool `json:"forceLogout" bson:"forceLogout"` + MFA bool `json:"mfa" bson:"mfa"` + Biometrics bool `json:"biometrics" bson:"biometrics"` + ForceLogout bool `json:"forceLogout" bson:"forceLogout"` + Credentials webauthn.Credential `json:"credentials" bson:"credentials"` } type Location struct { From 8bd505c071f238a4c771259b5343538f98aa27d2 Mon Sep 17 00:00:00 2001 From: Michael-u21546551 Date: Fri, 2 Aug 2024 20:35:14 +0200 Subject: [PATCH 05/20] chore: Add dev.json to .gitignore and update FinishRegistrationAdmin function in auth_handlers.go --- occupi-backend/.gitignore | 4 +- occupi-backend/pkg/handlers/auth_handlers.go | 58 +++++++++++++++++++- occupi-backend/pkg/router/router.go | 9 +-- 3 files changed, 65 insertions(+), 6 deletions(-) diff --git a/occupi-backend/.gitignore b/occupi-backend/.gitignore index c6eabc7e..5ade30fd 100644 --- a/occupi-backend/.gitignore +++ b/occupi-backend/.gitignore @@ -4,4 +4,6 @@ /web -*.exe \ No newline at end of file +*.exe + +dev.json \ No newline at end of file diff --git a/occupi-backend/pkg/handlers/auth_handlers.go b/occupi-backend/pkg/handlers/auth_handlers.go index 04504bc1..6ae990df 100644 --- a/occupi-backend/pkg/handlers/auth_handlers.go +++ b/occupi-backend/pkg/handlers/auth_handlers.go @@ -181,8 +181,64 @@ func BeginRegistrationAdmin(ctx *gin.Context, appsession *models.AppSession) { )) } -func FinishRegistrationAdmin(ctx *gin.Context, appsession *models.AppSession) { +func FinishRegistrationAdmin(ctx *gin.Context, appsession *models.AppSession, role string, cookies bool) { + var requestEmail models.RequestEmail + if err := ctx.ShouldBindBodyWithJSON(&requestEmail); err != nil { + ctx.JSON(http.StatusBadRequest, utils.ErrorResponse( + http.StatusBadRequest, + "Invalid request payload", + constants.InvalidRequestPayloadCode, + "Expected email field", + nil)) + return + } + + // fetch sessionData from the cache + sessionData, err := cache.GetSession(appsession, requestEmail.Email) + + if err != nil { + ctx.JSON(http.StatusInternalServerError, utils.InternalServerError()) + logrus.WithError(err).Error("Error fetching session data from cache") + return + } + + // get the user's credentials from the database + cred, err := database.GetUserCredentials(ctx, appsession, requestEmail.Email) + + if err != nil { + ctx.JSON(http.StatusInternalServerError, utils.InternalServerError()) + logrus.WithError(err).Error("Error fetching user credentials from database") + return + } + user := models.NewWebAuthnUser([]byte(requestEmail.Email), requestEmail.Email, requestEmail.Email, cred) + + credential, err := appsession.WebAuthn.FinishRegistration(user, *sessionData, ctx.Request) + + if err != nil { + ctx.JSON(http.StatusInternalServerError, utils.InternalServerError()) + logrus.WithError(err).Error("Error finishing login") + return + } + + err = database.AddUserCredential(ctx, appsession, requestEmail.Email, credential) + + if err != nil { + ctx.JSON(http.StatusInternalServerError, utils.InternalServerError()) + logrus.WithError(err).Error("Error finishing login") + return + } + + // generate a jwt token for the user + token, expirationTime, err := GenerateJWTTokenAndStartSession(ctx, appsession, requestEmail.Email, role) + + if err != nil { + logrus.WithError(err).Error("Error generating JWT token") + return + } + + // Use AllocateAuthTokens to handle the response + AllocateAuthTokens(ctx, token, expirationTime, cookies) } // handler for registering a new user on occupi /auth/register diff --git a/occupi-backend/pkg/router/router.go b/occupi-backend/pkg/router/router.go index a6534e26..c1a6a2cf 100644 --- a/occupi-backend/pkg/router/router.go +++ b/occupi-backend/pkg/router/router.go @@ -58,10 +58,11 @@ func OccupiRouter(router *gin.Engine, appsession *models.AppSession) { } auth := router.Group("/auth") { - auth.POST("/login", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.Login(ctx, appsession, constants.Basic, true) }) - auth.POST("/login-admin", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.Login(ctx, appsession, constants.Admin, true) }) - auth.POST("/login-mobile", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.Login(ctx, appsession, constants.Basic, false) }) - auth.POST("/login-admin-mobile", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.Login(ctx, appsession, constants.Admin, false) }) + auth.POST("/login", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.Login(ctx, appsession, constants.Basic, true, false) }) + auth.POST("/login-admin", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.Login(ctx, appsession, constants.Admin, true, false) }) + auth.POST("/login-admin-webauthn", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.Login(ctx, appsession, constants.Admin, true, true) }) + auth.POST("/login-mobile", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.Login(ctx, appsession, constants.Basic, false, false) }) + auth.POST("/login-admin-mobile", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.Login(ctx, appsession, constants.Admin, false, false) }) auth.POST("/register", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.Register(ctx, appsession) }) auth.POST("/resend-otp", func(ctx *gin.Context) { middleware.AttachOTPRateLimitMiddleware(ctx, appsession) }, func(ctx *gin.Context) { handlers.ResendOTP(ctx, appsession, constants.ReverifyEmail) }) auth.POST("/verify-otp", func(ctx *gin.Context) { handlers.VerifyOTP(ctx, appsession, false, constants.Basic, true) }) From 2aa2dc9b98137238cde6fbb6987b32436e0bb5b7 Mon Sep 17 00:00:00 2001 From: Michael-u21546551 Date: Sat, 3 Aug 2024 23:10:21 +0200 Subject: [PATCH 06/20] =?UTF-8?q?feat:=20backend=20webauthn=20implementati?= =?UTF-8?q?on=20is=20now=20working=F0=9F=8E=89!!!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- occupi-backend/static/index.html | 88 ++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 occupi-backend/static/index.html diff --git a/occupi-backend/static/index.html b/occupi-backend/static/index.html new file mode 100644 index 00000000..a881f6f4 --- /dev/null +++ b/occupi-backend/static/index.html @@ -0,0 +1,88 @@ + + + + + + WebAuthn Demo + + +

WebAuthn Demo

+ + + + + + From 06f4ce0acc1ab6324b7b6221b1efac7a1d3bb4a4 Mon Sep 17 00:00:00 2001 From: Michael-u21546551 Date: Sat, 3 Aug 2024 23:11:43 +0200 Subject: [PATCH 07/20] =?UTF-8?q?feat:=20wait=20the=20others=20were=20left?= =?UTF-8?q?=20behind=20lol,=20okay=20here=20are=20the=20real=20ones?= =?UTF-8?q?=F0=9F=AB=B5=F0=9F=92=AA=F0=9F=8F=8B=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- occupi-backend/configs/setup.go | 12 ++ occupi-backend/pkg/cache/cache.go | 21 ++-- occupi-backend/pkg/handlers/auth_handlers.go | 109 +++++++++++----- occupi-backend/pkg/handlers/auth_helpers.go | 11 +- occupi-backend/pkg/models/app.go | 42 ++++--- occupi-backend/pkg/models/request.go | 9 ++ occupi-backend/pkg/router/router.go | 6 +- occupi-backend/pkg/utils/utils.go | 11 ++ occupi-backend/static/index.html | 126 ++++++++++++------- 9 files changed, 239 insertions(+), 108 deletions(-) diff --git a/occupi-backend/configs/setup.go b/occupi-backend/configs/setup.go index 1cda8dab..5a08f4a6 100644 --- a/occupi-backend/configs/setup.go +++ b/occupi-backend/configs/setup.go @@ -89,6 +89,18 @@ func CreateCache() *bigcache.BigCache { return cache } +// Create cache for sessions +func CreateSessionCache() *bigcache.BigCache { + config := bigcache.DefaultConfig(time.Duration(GetCacheEviction()) * time.Second) // Set the eviction time to x seconds + config.CleanWindow = time.Duration(GetCacheEviction()/2) * time.Second // Set the cleanup interval to x seconds + cache, err := bigcache.New(context.Background(), config) + if err != nil { + logrus.Fatal(err) + } + + return cache +} + // create cache for rate limiting otp regenration requests func CreateOTPRateLimitCache() *bigcache.BigCache { config := bigcache.DefaultConfig(time.Duration(GetOTPReqEviction()) * time.Second) // Set the eviction time to x seconds diff --git a/occupi-backend/pkg/cache/cache.go b/occupi-backend/pkg/cache/cache.go index bd9e6e7d..c5200ded 100644 --- a/occupi-backend/pkg/cache/cache.go +++ b/occupi-backend/pkg/cache/cache.go @@ -4,7 +4,6 @@ import ( "errors" "github.com/COS301-SE-2024/occupi/occupi-backend/pkg/models" - "github.com/go-webauthn/webauthn/webauthn" "github.com/sirupsen/logrus" "go.mongodb.org/mongo-driver/bson" ) @@ -221,8 +220,8 @@ func DeleteImage(appsession *models.AppSession, id string) { } } -func SetSession(appsession *models.AppSession, session *webauthn.SessionData, email string) error { - if appsession.Cache == nil { +func SetSession(appsession *models.AppSession, session models.WebAuthnSession, uuid string) error { + if appsession.SessionCache == nil { return errors.New("cache not found") } @@ -234,7 +233,7 @@ func SetSession(appsession *models.AppSession, session *webauthn.SessionData, em } // set the session in the cache - if err := appsession.Cache.Set(SessionKey(email), sessionData); err != nil { + if err := appsession.SessionCache.Set(SessionKey(uuid), sessionData); err != nil { logrus.Error("failed to set session in cache", err) return err } @@ -242,14 +241,14 @@ func SetSession(appsession *models.AppSession, session *webauthn.SessionData, em return nil } -func GetSession(appsession *models.AppSession, email string) (*webauthn.SessionData, error) { - if appsession.Cache == nil { +func GetSession(appsession *models.AppSession, uuid string) (*models.WebAuthnSession, error) { + if appsession.SessionCache == nil { return nil, errors.New("cache not found") } // unmarshal the session from the cache - var session webauthn.SessionData - sessionData, err := appsession.Cache.Get(SessionKey(email)) + var session models.WebAuthnSession + sessionData, err := appsession.SessionCache.Get(SessionKey(uuid)) if err != nil { logrus.Error("key does not exist: ", err) @@ -264,13 +263,13 @@ func GetSession(appsession *models.AppSession, email string) (*webauthn.SessionD return &session, nil } -func DeleteSession(appsession *models.AppSession, email string) { - if appsession.Cache == nil { +func DeleteSession(appsession *models.AppSession, uuid string) { + if appsession.SessionCache == nil { return } // delete the session from the cache - if err := appsession.Cache.Delete(SessionKey(email)); err != nil { + if err := appsession.SessionCache.Delete(SessionKey(uuid)); err != nil { logrus.Error("failed to delete session from cache", err) return } diff --git a/occupi-backend/pkg/handlers/auth_handlers.go b/occupi-backend/pkg/handlers/auth_handlers.go index 6ae990df..aea6f399 100644 --- a/occupi-backend/pkg/handlers/auth_handlers.go +++ b/occupi-backend/pkg/handlers/auth_handlers.go @@ -1,6 +1,7 @@ package handlers import ( + "fmt" "net/http" "github.com/COS301-SE-2024/occupi/occupi-backend/configs" @@ -87,7 +88,7 @@ func Login(ctx *gin.Context, appsession *models.AppSession, role string, cookies AllocateAuthTokens(ctx, token, expirationTime, cookies) } -func FinishLoginAdmin(ctx *gin.Context, appsession *models.AppSession, role string, cookies bool) { +func BeginLoginAdmin(ctx *gin.Context, appsession *models.AppSession) { var requestEmail models.RequestEmail if err := ctx.ShouldBindBodyWithJSON(&requestEmail); err != nil { ctx.JSON(http.StatusBadRequest, utils.ErrorResponse( @@ -99,27 +100,72 @@ func FinishLoginAdmin(ctx *gin.Context, appsession *models.AppSession, role stri return } - // fetch sessionData from the cache - sessionData, err := cache.GetSession(appsession, requestEmail.Email) - + // Begin WebAuthn login process + cred, err := database.GetUserCredentials(ctx, appsession, requestEmail.Email) + if err != nil || len(cred.ID) == 0 { + ctx.JSON(http.StatusOK, utils.SuccessResponse( + http.StatusOK, + "Error getting user credentials, please register for WebAuthn", + gin.H{"error": "Error getting user credentials, please register for WebAuthn"})) + fmt.Printf("error getting user credentials: %v", err) + return + } + webauthnUser := models.NewWebAuthnUser([]byte(requestEmail.Email), requestEmail.Email, requestEmail.Email, cred) + options, sessionData, err := appsession.WebAuthn.BeginLogin(webauthnUser) if err != nil { ctx.JSON(http.StatusInternalServerError, utils.InternalServerError()) - logrus.WithError(err).Error("Error fetching session data from cache") + fmt.Printf("error beginning WebAuthn login: %v", err) return } - // get the user's credentials from the database - cred, err := database.GetUserCredentials(ctx, appsession, requestEmail.Email) + uuid := utils.GenerateUUID() + + session := models.WebAuthnSession{ + Uuid: uuid, + Email: requestEmail.Email, + Cred: cred, + SessionData: sessionData, + } + + // Save the session data - cache will expire in x defined minutes according to the config + if err := cache.SetSession(appsession, session, uuid); err != nil && err.Error() != "cache not found" { + ctx.JSON(http.StatusInternalServerError, utils.InternalServerError()) + fmt.Printf("error saving WebAuthn session data: %v", err) + return + } + + ctx.JSON(http.StatusOK, utils.SuccessResponse( + http.StatusOK, + "WebAuthn login initiated", + gin.H{"options": options, "sessionData": sessionData, "uuid": uuid}, + )) +} + +func FinishLoginAdmin(ctx *gin.Context, appsession *models.AppSession, role string, cookies bool) { + uuid := ctx.Param("id") + + if uuid == "" { + ctx.JSON(http.StatusBadRequest, utils.ErrorResponse( + http.StatusBadRequest, + "Invalid request payload", + constants.InvalidRequestPayloadCode, + "Expected id field", + nil)) + return + } + + // fetch sessionData from the cache + sessionData, err := cache.GetSession(appsession, uuid) if err != nil { ctx.JSON(http.StatusInternalServerError, utils.InternalServerError()) - logrus.WithError(err).Error("Error fetching user credentials from database") + logrus.WithError(err).Error("Error fetching session data from cache") return } - user := models.NewWebAuthnUser([]byte(requestEmail.Email), requestEmail.Email, requestEmail.Email, cred) + user := models.NewWebAuthnUser([]byte(sessionData.Email), sessionData.Email, sessionData.Email, sessionData.Cred) - credential, err := appsession.WebAuthn.FinishLogin(user, *sessionData, ctx.Request) + credential, err := appsession.WebAuthn.FinishLogin(user, *sessionData.SessionData, ctx.Request) if err != nil { ctx.JSON(http.StatusInternalServerError, utils.InternalServerError()) @@ -127,7 +173,7 @@ func FinishLoginAdmin(ctx *gin.Context, appsession *models.AppSession, role stri return } - err = database.AddUserCredential(ctx, appsession, requestEmail.Email, credential) + err = database.AddUserCredential(ctx, appsession, sessionData.Email, credential) if err != nil { ctx.JSON(http.StatusInternalServerError, utils.InternalServerError()) @@ -136,7 +182,7 @@ func FinishLoginAdmin(ctx *gin.Context, appsession *models.AppSession, role stri } // generate a jwt token for the user - token, expirationTime, err := GenerateJWTTokenAndStartSession(ctx, appsession, requestEmail.Email, role) + token, expirationTime, err := GenerateJWTTokenAndStartSession(ctx, appsession, sessionData.Email, role) if err != nil { logrus.WithError(err).Error("Error generating JWT token") @@ -167,8 +213,17 @@ func BeginRegistrationAdmin(ctx *gin.Context, appsession *models.AppSession) { return } + uuid := utils.GenerateUUID() + + session := models.WebAuthnSession{ + Uuid: uuid, + Email: requestEmail.Email, + Cred: webauthn.Credential{}, + SessionData: sessionData, + } + // Save the session data - cache will expire in x defined minutes according to the config - if err := cache.SetSession(appsession, sessionData, requestEmail.Email); err != nil { + if err := cache.SetSession(appsession, session, uuid); err != nil && err.Error() != "cache not found" { logrus.WithError(err).Error("Error saving session data in cache") ctx.JSON(http.StatusInternalServerError, utils.InternalServerError()) return @@ -177,24 +232,25 @@ func BeginRegistrationAdmin(ctx *gin.Context, appsession *models.AppSession) { ctx.JSON(http.StatusOK, utils.SuccessResponse( http.StatusOK, "WebAuthn login initiated", - gin.H{"options": options, "sessionData": sessionData}, + gin.H{"options": options, "sessionData": sessionData, "uuid": uuid}, )) } func FinishRegistrationAdmin(ctx *gin.Context, appsession *models.AppSession, role string, cookies bool) { - var requestEmail models.RequestEmail - if err := ctx.ShouldBindBodyWithJSON(&requestEmail); err != nil { + uuid := ctx.Param("id") + + if uuid == "" { ctx.JSON(http.StatusBadRequest, utils.ErrorResponse( http.StatusBadRequest, "Invalid request payload", constants.InvalidRequestPayloadCode, - "Expected email field", + "Expected id field", nil)) return } // fetch sessionData from the cache - sessionData, err := cache.GetSession(appsession, requestEmail.Email) + sessionData, err := cache.GetSession(appsession, uuid) if err != nil { ctx.JSON(http.StatusInternalServerError, utils.InternalServerError()) @@ -202,18 +258,9 @@ func FinishRegistrationAdmin(ctx *gin.Context, appsession *models.AppSession, ro return } - // get the user's credentials from the database - cred, err := database.GetUserCredentials(ctx, appsession, requestEmail.Email) - - if err != nil { - ctx.JSON(http.StatusInternalServerError, utils.InternalServerError()) - logrus.WithError(err).Error("Error fetching user credentials from database") - return - } - - user := models.NewWebAuthnUser([]byte(requestEmail.Email), requestEmail.Email, requestEmail.Email, cred) + user := models.NewWebAuthnUser([]byte(sessionData.Email), sessionData.Email, sessionData.Email, sessionData.Cred) - credential, err := appsession.WebAuthn.FinishRegistration(user, *sessionData, ctx.Request) + credential, err := appsession.WebAuthn.FinishRegistration(user, *sessionData.SessionData, ctx.Request) if err != nil { ctx.JSON(http.StatusInternalServerError, utils.InternalServerError()) @@ -221,7 +268,7 @@ func FinishRegistrationAdmin(ctx *gin.Context, appsession *models.AppSession, ro return } - err = database.AddUserCredential(ctx, appsession, requestEmail.Email, credential) + err = database.AddUserCredential(ctx, appsession, sessionData.Email, credential) if err != nil { ctx.JSON(http.StatusInternalServerError, utils.InternalServerError()) @@ -230,7 +277,7 @@ func FinishRegistrationAdmin(ctx *gin.Context, appsession *models.AppSession, ro } // generate a jwt token for the user - token, expirationTime, err := GenerateJWTTokenAndStartSession(ctx, appsession, requestEmail.Email, role) + token, expirationTime, err := GenerateJWTTokenAndStartSession(ctx, appsession, sessionData.Email, role) if err != nil { logrus.WithError(err).Error("Error generating JWT token") diff --git a/occupi-backend/pkg/handlers/auth_helpers.go b/occupi-backend/pkg/handlers/auth_helpers.go index a0754911..f336a96b 100644 --- a/occupi-backend/pkg/handlers/auth_helpers.go +++ b/occupi-backend/pkg/handlers/auth_helpers.go @@ -565,8 +565,17 @@ func WebAuthNAuthentication(ctx *gin.Context, appsession *models.AppSession, req return fmt.Errorf("error beginning WebAuthn login: %v", err) } + uuid := utils.GenerateUUID() + + session := models.WebAuthnSession{ + Uuid: uuid, + Email: requestUser.Email, + Cred: cred, + SessionData: sessionData, + } + // Save the session data - cache will expire in x defined minutes according to the config - if err := cache.SetSession(appsession, sessionData, requestUser.Email); err != nil { + if err := cache.SetSession(appsession, session, requestUser.Email); err != nil { ctx.JSON(http.StatusInternalServerError, utils.InternalServerError()) return fmt.Errorf("error saving WebAuthn session data: %v", err) } diff --git a/occupi-backend/pkg/models/app.go b/occupi-backend/pkg/models/app.go index 879c6c76..00411197 100644 --- a/occupi-backend/pkg/models/app.go +++ b/occupi-backend/pkg/models/app.go @@ -14,16 +14,17 @@ import ( // state management for the web app during runtime type AppSession struct { - DB *mongo.Client - Cache *bigcache.BigCache - EmailsSent int - CurrentDate time.Time - OtpReqCache *bigcache.BigCache - IPInfo *ipinfo.Client - RabbitMQ *amqp.Connection - RabbitCh *amqp.Channel - RabbitQ amqp.Queue - WebAuthn *webauthn.WebAuthn + DB *mongo.Client + Cache *bigcache.BigCache + EmailsSent int + CurrentDate time.Time + OtpReqCache *bigcache.BigCache + IPInfo *ipinfo.Client + RabbitMQ *amqp.Connection + RabbitCh *amqp.Channel + RabbitQ amqp.Queue + WebAuthn *webauthn.WebAuthn + SessionCache *bigcache.BigCache } // constructor for app session @@ -32,16 +33,17 @@ func New(db *mongo.Client, cache *bigcache.BigCache) *AppSession { ch := configs.CreateRabbitChannel(conn) q := configs.CreateRabbitQueue(ch) return &AppSession{ - DB: db, - Cache: cache, - EmailsSent: 0, - CurrentDate: time.Now(), - OtpReqCache: configs.CreateOTPRateLimitCache(), - IPInfo: configs.CreateIPInfoClient(), - RabbitMQ: conn, - RabbitCh: ch, - RabbitQ: q, - WebAuthn: configs.CreateWebAuthnInstance(), + DB: db, + Cache: cache, + EmailsSent: 0, + CurrentDate: time.Now(), + OtpReqCache: configs.CreateOTPRateLimitCache(), + IPInfo: configs.CreateIPInfoClient(), + RabbitMQ: conn, + RabbitCh: ch, + RabbitQ: q, + WebAuthn: configs.CreateWebAuthnInstance(), + SessionCache: configs.CreateSessionCache(), } } diff --git a/occupi-backend/pkg/models/request.go b/occupi-backend/pkg/models/request.go index 2f96c4bd..bc6d5b83 100644 --- a/occupi-backend/pkg/models/request.go +++ b/occupi-backend/pkg/models/request.go @@ -1,5 +1,7 @@ package models +import "github.com/go-webauthn/webauthn/webauthn" + type RegisterUser struct { Email string `json:"email" binding:"required,email"` Password string `json:"password" binding:"required,min=8"` @@ -102,3 +104,10 @@ type RequestRoom struct { RoomName string `json:"roomName" binding:"required"` Resources []string `json:"resources" binding:"required"` } + +type WebAuthnSession struct { + Uuid string `json:"uuid"` + Email string `json:"email"` + Cred webauthn.Credential `json:"cred"` + SessionData *webauthn.SessionData `json:"sessionData"` +} diff --git a/occupi-backend/pkg/router/router.go b/occupi-backend/pkg/router/router.go index c1a6a2cf..0beecdac 100644 --- a/occupi-backend/pkg/router/router.go +++ b/occupi-backend/pkg/router/router.go @@ -58,9 +58,13 @@ func OccupiRouter(router *gin.Engine, appsession *models.AppSession) { } auth := router.Group("/auth") { + auth.POST("/login-admin-begin", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.BeginLoginAdmin(ctx, appsession) }) + auth.POST("/login-admin-finish/:id", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.FinishLoginAdmin(ctx, appsession, constants.Admin, false) }) + auth.POST("/register-admin-begin", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.BeginRegistrationAdmin(ctx, appsession) }) + auth.POST("/register-admin-finish/:id", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.FinishRegistrationAdmin(ctx, appsession, constants.Admin, false) }) + auth.POST("/login", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.Login(ctx, appsession, constants.Basic, true, false) }) auth.POST("/login-admin", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.Login(ctx, appsession, constants.Admin, true, false) }) - auth.POST("/login-admin-webauthn", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.Login(ctx, appsession, constants.Admin, true, true) }) auth.POST("/login-mobile", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.Login(ctx, appsession, constants.Basic, false, false) }) auth.POST("/login-admin-mobile", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.Login(ctx, appsession, constants.Admin, false, false) }) auth.POST("/register", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.Register(ctx, appsession) }) diff --git a/occupi-backend/pkg/utils/utils.go b/occupi-backend/pkg/utils/utils.go index f4e9cf2a..9456ec36 100644 --- a/occupi-backend/pkg/utils/utils.go +++ b/occupi-backend/pkg/utils/utils.go @@ -21,6 +21,7 @@ import ( "github.com/gin-contrib/sessions" "github.com/gin-gonic/gin" "github.com/go-playground/validator" + "github.com/google/uuid" "github.com/microcosm-cc/bluemonday" "github.com/nfnt/resize" "github.com/sirupsen/logrus" @@ -660,3 +661,13 @@ func ConvertImageToBytes(file *multipart.FileHeader, width uint, thumbnail bool) return buf.Bytes(), nil } + +func GenerateUUID() string { + uuid, err := uuid.NewRandom() + + if err != nil { + return "" + } + + return uuid.String() +} diff --git a/occupi-backend/static/index.html b/occupi-backend/static/index.html index a881f6f4..c9cbda2c 100644 --- a/occupi-backend/static/index.html +++ b/occupi-backend/static/index.html @@ -7,7 +7,6 @@

WebAuthn Demo

- From 27bdae48df041297fbb2808be57ccc962565311f Mon Sep 17 00:00:00 2001 From: Michael-u21546551 Date: Sun, 4 Aug 2024 12:08:59 +0200 Subject: [PATCH 08/20] =?UTF-8?q?chore=F0=9F=A7=B9:=20small=20webauthn=20c?= =?UTF-8?q?leanup=20and=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- occupi-backend/configs/config.yaml.gpg | Bin 393 -> 391 bytes occupi-backend/configs/dev.deployed.yaml.gpg | Bin 981 -> 1012 bytes occupi-backend/configs/dev.localhost.yaml.gpg | Bin 928 -> 936 bytes occupi-backend/configs/prod.yaml.gpg | Bin 971 -> 1004 bytes occupi-backend/configs/test.yaml.gpg | Bin 866 -> 863 bytes occupi-backend/pkg/handlers/auth_handlers.go | 46 +++++++++++++----- occupi-backend/pkg/handlers/auth_helpers.go | 42 ---------------- occupi-backend/pkg/models/request.go | 2 +- occupi-backend/pkg/router/router.go | 12 ++--- occupi-backend/static/README.md | 10 ++++ occupi-backend/static/index.html | 22 ++++++++- occupi-backend/static/main.py | 8 +++ 12 files changed, 80 insertions(+), 62 deletions(-) create mode 100644 occupi-backend/static/README.md create mode 100644 occupi-backend/static/main.py diff --git a/occupi-backend/configs/config.yaml.gpg b/occupi-backend/configs/config.yaml.gpg index 6ffd414dd1dc63cb77e887977f39f67b2fc562bc..44c6fc3874f4cc11692d4e3c8e5ca80c4fe6b772 100644 GIT binary patch literal 391 zcmV;20eJq54Fm}T0;3uwCEnvsN&nKowE=zT{%cn%iBbhkWSgxh3U_7RzmMCs!9+La zXd8n42E5_oJZc_9N4VCr`m?@H-u zCp|W;Gh~MDg|s@ujR5t9{vP@@6`3F>mkw{euI<-x!Ut^{X_5P;X}l?Ffl zx=+d9UwZvWj?4xM*g2^9q})fkWn07Sxitw_^8phLA`8cEG<1MZg2h=wv)M3D-OTd&DX; z+j_ck?C0>kyKN2WZvJkYouLm%p&72_Z|w`}5!<$J$%IUe!>9|8GVBiP1OfH2%#RMv(=`itr`y|*UOWjahk-_I3Ox7_=uW!AL1`HD{%3)X4Z4c l&l{?>gz%tke#%>i9bGt>fKosEZUfBFs?Ltb7Ym*D*6#o!lLB!k9AH}-5c+P6wy1l>^4ai z$P%zMSl>k?S>TA?8!-2T`jJswx_NkoMy`0K81tGlHn5618v(-TL(P+8wW_ovU}S}2 z5!{y@O!1_Zy?K*%6%cgFTWt1{80`X#M+-|qkCpXlXx!5lQWZP&BjUdG_`|Z*WoR%6 z$zv@tIm>5QO;^gm$}JfWN|}29H^Khb=2Q;EmW~?fHi(>4!=5oD$3UM_qUePEbAGip z&dTOKe5ENKIFo0B{t~Nw_ajVf8fyhm=8fzn$}_)V&psS`1E z)$Pr|!?EbBHz89b2ys_L2m!p3g1mk*+(f5al#2dsZ diff --git a/occupi-backend/configs/dev.deployed.yaml.gpg b/occupi-backend/configs/dev.deployed.yaml.gpg index d21ea2a50e3dceae2e431b6544533b1fbacaba99..6f65e4d4ce19e96364e732478df0df9fe699609e 100644 GIT binary patch literal 1012 zcmV1+0Uk|%EhXE4w5@9Pa9o$A@~#i+dVBR;Gl{BD ztfNI-JMY8(ojNE1Na8)c-M)YC@~%{i&JjZ^9D^=2%uxh3ldBLjUc6D?DbT2sFkA^Km) zYnMGdam)B?8?@P_#x>Sg(Bj8-d}Ma9fjVnND_b}M#o?Qk!F{CDc<=;1SyKB7`W?Mw zn>RZTY^{v2rJRHe(iIz6NfH~&=Yf1B4yl<$9cqS+$c1jI>3a4!iAV37A$Px%_5Glr z1_600 z?oFavWrFP_^Bj4odRgP9%8&}aYAhemGlsmP=wNBzx1S|_W8BV1?-GKvEJqp{88s02 z-v}M zgs=nlQHlB25t9*p`jqHI}r7% zo(B7PI0m=NF#U>86XdoA}a;$TfRh@4FB z&X{ksVI;770iWhQMXuU;bQ@x+DWy@GKUZRhi04@5^SIi|8vW#w5D|$!Pd1@F!mv+_ z^|nY`^{?homSq&nyENAs&QQ9$!D5;;HCWm%2TdMpK+xwv?!w#zfqxH;@shP=L?{wT zSNms7t!=az;DwQBwu%>PR7r582D&4-s)@}c%=zDIMCd*lflpROTbtjQ%tdYK;R?^c z8J&pmm=GIUX~C#HddBUW!Ao7E=r2lo>^4O;M@zY=_pIUR{cqwOtiFHJH-*MmcJZ#s ivVG9;=|I5uM9L1(@b^zJgr#tws%Q4O2RZ%|gxjY+5B4np literal 981 zcmV;`11kKC4Fm}T0xD1~ump-1e*e7@HNvxYli!#Hk9G0nIM{?&V1Ap;re`bm@%yM%ti3oO=bscc`lk18` z5d1{W+X?^Wi^7g($zs1~R&af66u~djq(@9qdEWeau4M}0cKda;Sw>;atkzMhaU3dV zS_UjyYn-JP^c*lXy(}LkI`gS>F9fuE$)@!K{zHGg-qqoRT&+LQ(rx!Mwju9b5pV*` z4u1Z_4#=HsUj-_l8Lmcx85%vN1Y+fX2IG-M1>2(?UX6AFuOYNee=keWS(K`gZ`2i_ zaOmtMUZ-VRHQX~LKwr+VjTT+!#e|Iv^sTI*sMQB;O~dEL#96xG9nQE?*&k=|0CBPO zhGAM}S2%COt53%-;|N5!-azybA=U%g-<*u+0fJQLya31JGNPYH17wsVRa5iIk|R?A zT}b3+7E`5^2=42|Jw4rPwv9|hbv1W8wU;Z0E0L@UX1V$`bMUJ;xuX2bfFr(CW%yNw z^mN5R8Wy+=j80u`WSwO1sWis@)1*(UPU4t?_ydX(N{;ccZvwG@-3}4s{;$fNv8nZu zBmK9qS(^F7jan*mIG3hFNcBMM{VSUZQd0&0GRfO1fZ&nfccGfO_mp!X+RgYn?(q#k Dwz1=@ diff --git a/occupi-backend/configs/dev.localhost.yaml.gpg b/occupi-backend/configs/dev.localhost.yaml.gpg index bc1cfc110da5d5f4b7e50141259e30c61c856f43..f0d357cecd97e9fa0d0a56fcdfa09486a85d0b59 100644 GIT binary patch literal 936 zcmV;Z16TZv4Fm}T0ul5QHn@~8#sAXj0Ub{$cS(RRV>qpK=U${X3(bpsV4}grj#yx} z?2HGWId`N2o|p;0cRIgrh%?2Nuoy--b`n~rx?#-0d3YvaZ#`0t+CIDCEJI^eCX*}V zbh>@(hz3cY7=z5(diA2;&%fgpmSoB@FH?nP&(58Vm5+ON(%m-l?+Bq zWxl^T2FolU)h!{hZq|At%%!I2981bGUSkIfhyV$M%QJWtZsZ~|sc|AoXX1sgoDvcn zp!hS)N6kdWIa;J68XU|tcGIclu>=tf(vus*$ZIj zJbOaBrt7X1DKO&dXbyzMr@v7>8j5lW$1^dmSF^p)BQv=b2A(B!M&DS4ax?>pSHQ4e z3zLQGpp!(C1BkVrUXfHTz}3!O6tZ!@H{fEJ4c)CviFuVx{g?ph!2>%#6MZD`H8072 zt{aSVg0hVO5Ft7!{Tk-;-Af)_GOfu{fd!s8__)E4_{^9?EV61V8tUbxB<8oSz~xbY zXK1b#(qe#DN~eaZ(_WTg#31))Z^m!tC^VO{T-af_mV7m{@qA4T3XQo^RZiweTtql% z@isgtLg4~Qw$v%-=G|B&Yu|w5xjU=M?e4Y4@gki+EMhpb1sU_d0}{$#!g-ga`MqAj zJPOVh(3LEUFs_g1U4m*QI;FQ`OX=%+vo@%N6H9cxI1rWa`` zD1)Aw9E16YO&wZS8MgE-l+APO7a$;=9{isB%QUQ{Ps^20i|}ovH7zn)K+Z`g7$(;Y KiYVL-p~V*%3&kw} literal 928 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 diff --git a/occupi-backend/configs/test.yaml.gpg b/occupi-backend/configs/test.yaml.gpg index 722b61a8f8ab8485367b7cd3baa5b66779be50b7..31baf76540d3241cfc43ae733885c8af25d59924 100644 GIT binary patch literal 863 zcmV-l1EBnj4Fm}T0-x&SELr&@0{_zK0r}%M1CN6NFHO0N2C$IK%V2;?ybaJpDR#d+ z!C!Z58wt&Y|3JDOZ}6GH7+8f0V)O9=X}~eaqnZuS<>=Nc!$;@XFW8e;>F= zwOjQ^kkj=a6R&NgLqgWVUWh7nro#rPOz20Je#az)(4QaY-+y0gu3fnwZ07^8y-pO1 z7Ocli!dk?S@GIq9Tty8{U#Vx;#B!rr<8%)}3Umt%xQlh~=)mC| zqaFFgyR#QUV#5_aBHUf5$dYZCqQ-3~SiKb*#%*V1EHIK!EIqlDId zC68NkC2^r^mX5i0cO{?tvnBc`+~+Mr_dTz%@(B~RQeLmia3^alIm#wKMcvYB!fHrA((608`3&)s@!^+09zfCKJ6gagfK zlv*OOdT4yMw8DxX%5fmAXXk$7u(eDAgstTl^AM<;1066hjr<bCgQ~zCu4k1 z%cD`QZBPAA&4oSY_bgg5z>IXN3TcLLg~GMeF$)Us#YT2)ht+u@u12_AqOv5aMW*(0 zzj^&zgnb7-aZ7Lry$KZ@pubcPh7dTF-R7A(SxMR6V?!v>Ih@O?yAmGoHp3MoMbL{G zE^f9zgoDyj{{2gHTbM+Ny}YzRx-`BPeIe=OLnOqt^-LD0X#{|axS|2z<~u^oMpj@vAPGJJ-uZ}IcI1HC?g*SfggX^zECK}2M>XgEmeC1zikp1m p73Z-RxHnV&NhV3uXdXL)p(&c72) z!}KSdKnGniv(f4K7LS#LE#CO2v2f~v<40?QTof)r$~TQ%`4R5`iv6|pGM;C-ORbO#O??A!F5?f;3!0HLd!En%=@F#OT6{weNWFs%zuF_>` zA3HI5+de(wXBC+07;n3htEMNP&j2%*=mKAXcvyN_y{DnDVR6$nXg%^ygm|{Dqe?8@ z#NGE-6rY*HR5a{&UmgjEGilc;9d{{RU3ZE_!uZi9Urm7d+L{~WF0(fRH82fCcjKC%)o0$cM72=-A~9&gr! zntel*hMy&FQD1-zT4~y5PXjK*RZ{^VR~ZmE`F$)a7pJi}p2&;&Y3PhRJ5Dep7ySM~ zC&mM}&oXf3*aMJ2NU=c?ciQcov~@P+CaYkoT9?D=u_hQ%-_G2e9N2xdEt;`c+{|Z< zB}w2b+YnoeT5a9~3tw^8R>O$KY3CTTEMFW{kYJDi z+=d!BqAiPNWx)&`Rm|62BUj!C!jCD;#jy|hEyHbgib1sBU%UHCZZS*pz`RZ7#_P(< z1Jl#DB8iEK=*zjYb%M*Szq&v##!_v+BKL^Z()`8O0hFyjdF=@(L;+CdU>j&Y&Nv#= zJTmMm41N?C8N<#c5z1S0ZN!c8{x6#%_Djuqy48Ub%5jiN<5d+03G(P#rKQH07y89T zK%HFU;`?;R?psV3+8hYai!9p6IOeRzCFEBqud~rOE|A1Mdb4Nwu_G{1-JMcNo~)}< s!|NC=iD8TY%pOQ4$pE1tA^xI`Bwx!2Pl8xRNL>soH9A<7b7Mo_Y8?KbcmMzZ diff --git a/occupi-backend/pkg/handlers/auth_handlers.go b/occupi-backend/pkg/handlers/auth_handlers.go index aea6f399..a520c671 100644 --- a/occupi-backend/pkg/handlers/auth_handlers.go +++ b/occupi-backend/pkg/handlers/auth_handlers.go @@ -18,7 +18,7 @@ import ( ) // handler for logging a new user on occupi /auth/login -func Login(ctx *gin.Context, appsession *models.AppSession, role string, cookies bool, shouldWebAuthN bool) { +func Login(ctx *gin.Context, appsession *models.AppSession, role string, cookies bool) { var requestUser models.RequestUser if err := ctx.ShouldBindBodyWithJSON(&requestUser); err != nil { ctx.JSON(http.StatusBadRequest, utils.ErrorResponse( @@ -68,14 +68,6 @@ func Login(ctx *gin.Context, appsession *models.AppSession, role string, cookies return } - if shouldWebAuthN { - err := WebAuthNAuthentication(ctx, appsession, requestUser) - if err != nil { - logrus.WithError(err).Error("Error with WebAuthN authentication") - } - return - } - // generate a jwt token for the user token, expirationTime, err := GenerateJWTTokenAndStartSession(ctx, appsession, requestUser.Email, role) @@ -100,6 +92,22 @@ func BeginLoginAdmin(ctx *gin.Context, appsession *models.AppSession) { return } + // validate email exists + if valid, err := ValidateEmailExists(ctx, appsession, requestEmail.Email); !valid { + if err != nil { + logrus.WithError(err).Error("Error validating email") + } + return + } + + // pre-login checks + if success, err := PreLoginAccountChecks(ctx, appsession, requestEmail.Email, constants.Admin); !success { + if err != nil { + logrus.WithError(err).Error("Error validating email") + } + return + } + // Begin WebAuthn login process cred, err := database.GetUserCredentials(ctx, appsession, requestEmail.Email) if err != nil || len(cred.ID) == 0 { @@ -121,7 +129,7 @@ func BeginLoginAdmin(ctx *gin.Context, appsession *models.AppSession) { uuid := utils.GenerateUUID() session := models.WebAuthnSession{ - Uuid: uuid, + UUID: uuid, Email: requestEmail.Email, Cred: cred, SessionData: sessionData, @@ -205,6 +213,22 @@ func BeginRegistrationAdmin(ctx *gin.Context, appsession *models.AppSession) { return } + // validate email exists + if valid, err := ValidateEmailExists(ctx, appsession, requestEmail.Email); !valid { + if err != nil { + logrus.WithError(err).Error("Error validating email") + } + return + } + + // pre-login checks + if success, err := PreLoginAccountChecks(ctx, appsession, requestEmail.Email, constants.Admin); !success { + if err != nil { + logrus.WithError(err).Error("Error validating email") + } + return + } + webauthnUser := models.NewWebAuthnUser([]byte(requestEmail.Email), requestEmail.Email, requestEmail.Email, webauthn.Credential{}) options, sessionData, err := appsession.WebAuthn.BeginRegistration(webauthnUser) if err != nil { @@ -216,7 +240,7 @@ func BeginRegistrationAdmin(ctx *gin.Context, appsession *models.AppSession) { uuid := utils.GenerateUUID() session := models.WebAuthnSession{ - Uuid: uuid, + UUID: uuid, Email: requestEmail.Email, Cred: webauthn.Credential{}, SessionData: sessionData, diff --git a/occupi-backend/pkg/handlers/auth_helpers.go b/occupi-backend/pkg/handlers/auth_helpers.go index f336a96b..9a490a44 100644 --- a/occupi-backend/pkg/handlers/auth_helpers.go +++ b/occupi-backend/pkg/handlers/auth_helpers.go @@ -1,13 +1,11 @@ package handlers import ( - "fmt" "net/http" "time" "github.com/COS301-SE-2024/occupi/occupi-backend/configs" "github.com/COS301-SE-2024/occupi/occupi-backend/pkg/authenticator" - "github.com/COS301-SE-2024/occupi/occupi-backend/pkg/cache" "github.com/COS301-SE-2024/occupi/occupi-backend/pkg/constants" "github.com/COS301-SE-2024/occupi/occupi-backend/pkg/database" "github.com/COS301-SE-2024/occupi/occupi-backend/pkg/mail" @@ -547,43 +545,3 @@ func AttemptToSignNewEmail(ctx *gin.Context, appsession *models.AppSession, emai )) } } - -func WebAuthNAuthentication(ctx *gin.Context, appsession *models.AppSession, requestUser models.RequestUser) error { - // Begin WebAuthn login process - cred, err := database.GetUserCredentials(ctx, appsession, requestUser.Email) - if err != nil { - ctx.JSON(http.StatusOK, utils.SuccessResponse( - http.StatusOK, - "Error getting user credentials, please register for WebAuthn", - gin.H{"error": "Error getting user credentials, please register for WebAuthn"})) - return fmt.Errorf("error getting user credentials: %v", err) - } - webauthnUser := models.NewWebAuthnUser([]byte(requestUser.Email), requestUser.Email, requestUser.Email, cred) - options, sessionData, err := appsession.WebAuthn.BeginLogin(webauthnUser) - if err != nil { - ctx.JSON(http.StatusInternalServerError, utils.InternalServerError()) - return fmt.Errorf("error beginning WebAuthn login: %v", err) - } - - uuid := utils.GenerateUUID() - - session := models.WebAuthnSession{ - Uuid: uuid, - Email: requestUser.Email, - Cred: cred, - SessionData: sessionData, - } - - // Save the session data - cache will expire in x defined minutes according to the config - if err := cache.SetSession(appsession, session, requestUser.Email); err != nil { - ctx.JSON(http.StatusInternalServerError, utils.InternalServerError()) - return fmt.Errorf("error saving WebAuthn session data: %v", err) - } - - ctx.JSON(http.StatusOK, utils.SuccessResponse( - http.StatusOK, - "WebAuthn login initiated", - gin.H{"options": options, "sessionData": sessionData}, - )) - return nil -} diff --git a/occupi-backend/pkg/models/request.go b/occupi-backend/pkg/models/request.go index bc6d5b83..383fbf3c 100644 --- a/occupi-backend/pkg/models/request.go +++ b/occupi-backend/pkg/models/request.go @@ -106,7 +106,7 @@ type RequestRoom struct { } type WebAuthnSession struct { - Uuid string `json:"uuid"` + UUID string `json:"uuid"` Email string `json:"email"` Cred webauthn.Credential `json:"cred"` SessionData *webauthn.SessionData `json:"sessionData"` diff --git a/occupi-backend/pkg/router/router.go b/occupi-backend/pkg/router/router.go index 0beecdac..8a3abecd 100644 --- a/occupi-backend/pkg/router/router.go +++ b/occupi-backend/pkg/router/router.go @@ -59,14 +59,14 @@ func OccupiRouter(router *gin.Engine, appsession *models.AppSession) { auth := router.Group("/auth") { auth.POST("/login-admin-begin", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.BeginLoginAdmin(ctx, appsession) }) - auth.POST("/login-admin-finish/:id", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.FinishLoginAdmin(ctx, appsession, constants.Admin, false) }) + auth.POST("/login-admin-finish/:id", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.FinishLoginAdmin(ctx, appsession, constants.Admin, true) }) auth.POST("/register-admin-begin", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.BeginRegistrationAdmin(ctx, appsession) }) - auth.POST("/register-admin-finish/:id", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.FinishRegistrationAdmin(ctx, appsession, constants.Admin, false) }) + auth.POST("/register-admin-finish/:id", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.FinishRegistrationAdmin(ctx, appsession, constants.Admin, true) }) - auth.POST("/login", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.Login(ctx, appsession, constants.Basic, true, false) }) - auth.POST("/login-admin", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.Login(ctx, appsession, constants.Admin, true, false) }) - auth.POST("/login-mobile", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.Login(ctx, appsession, constants.Basic, false, false) }) - auth.POST("/login-admin-mobile", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.Login(ctx, appsession, constants.Admin, false, false) }) + auth.POST("/login", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.Login(ctx, appsession, constants.Basic, true) }) + auth.POST("/login-admin", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.Login(ctx, appsession, constants.Admin, true) }) + auth.POST("/login-mobile", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.Login(ctx, appsession, constants.Basic, false) }) + auth.POST("/login-admin-mobile", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.Login(ctx, appsession, constants.Admin, false) }) auth.POST("/register", middleware.UnProtectedRoute, func(ctx *gin.Context) { handlers.Register(ctx, appsession) }) auth.POST("/resend-otp", func(ctx *gin.Context) { middleware.AttachOTPRateLimitMiddleware(ctx, appsession) }, func(ctx *gin.Context) { handlers.ResendOTP(ctx, appsession, constants.ReverifyEmail) }) auth.POST("/verify-otp", func(ctx *gin.Context) { handlers.VerifyOTP(ctx, appsession, false, constants.Basic, true) }) diff --git a/occupi-backend/static/README.md b/occupi-backend/static/README.md new file mode 100644 index 00000000..0b5e1f72 --- /dev/null +++ b/occupi-backend/static/README.md @@ -0,0 +1,10 @@ +1. To run the script, open ubuntu terminal and install python3 with: +``` +sudo apt update +sudo apt install python3 +``` + +2. Run script with: +```python3 main.py``` + +NB: Be careful, in the index.html, the fetch requests access "http://localhost:8080", that may need to be changed. Also not that the email and password are not valid and are just for test. \ No newline at end of file diff --git a/occupi-backend/static/index.html b/occupi-backend/static/index.html index c9cbda2c..c281a72f 100644 --- a/occupi-backend/static/index.html +++ b/occupi-backend/static/index.html @@ -10,12 +10,17 @@

WebAuthn Demo