...
1 package barcode
2
3 import (
4 "fmt"
5 "net/http"
6 "strings"
7
8 "edge-infra.dev/pkg/edge/iam/apperror"
9 "edge-infra.dev/pkg/edge/iam/config"
10 "edge-infra.dev/pkg/edge/iam/device"
11 "edge-infra.dev/pkg/edge/iam/profile"
12 "edge-infra.dev/pkg/edge/iam/prometheus"
13 "edge-infra.dev/pkg/edge/iam/util"
14
15 "github.com/gin-gonic/gin"
16 "github.com/google/uuid"
17 "github.com/gorilla/sessions"
18 )
19
20 type emergencyBarcodeRequest struct {
21 Username string `form:"username"`
22 Reason string `form:"reason"`
23 }
24 type Emergency struct {
25 profileStorage profile.Storage
26 sessionStore sessions.Store
27 deviceStorage device.Storage
28 }
29
30 func NewEmergency(router *gin.Engine, sessionStore sessions.Store, storage interface{}, _ *prometheus.Metrics) *Emergency {
31 emergency := &Emergency{
32 profileStorage: storage.(profile.Storage),
33 sessionStore: sessionStore,
34 deviceStorage: storage.(device.Storage),
35 }
36
37 router.POST("/idp/handle-emergency", util.MakeHandlerFunc(emergency.handleEBCRequest))
38 return emergency
39 }
40
41 func (emergency *Emergency) handleEBCRequest(c *gin.Context) error {
42 var form emergencyBarcodeRequest
43 if err := c.ShouldBind(&form); err != nil {
44 return apperror.NewAbortError(
45 fmt.Errorf("invalid emergency barcode request: %w", err),
46 http.StatusBadRequest)
47 }
48
49 form.Username = strings.ToLower(form.Username)
50 session, _ := emergency.sessionStore.Get(c.Request, "oauth2")
51 switch form.Reason {
52 case "11":
53 session.Values["reason"] = form.Reason
54 default:
55 var subject string
56 if config.DeviceLoginEnabled() {
57 acc, err := emergency.deviceStorage.GetDeviceAccount(c, form.Username)
58 if err != nil {
59 return apperror.NewAbortError(
60 fmt.Errorf("failed to get a device account: %w", err),
61 http.StatusInternalServerError)
62 }
63 if acc == nil {
64
65 return apperror.NewAbortError(
66 fmt.Errorf("device account not found (devicelogin=`%v`): %w", form.Username, err),
67 http.StatusBadRequest)
68 }
69 subject = acc.Subject
70 } else {
71 subject = form.Username
72 }
73 userProfile, err := emergency.profileStorage.GetIdentityProfile(c, subject)
74 if err != nil {
75 return apperror.NewAbortError(
76 fmt.Errorf("failed to get user profile: %w", err),
77 http.StatusInternalServerError)
78 }
79
80 if userProfile == nil {
81
82 return apperror.NewAbortError(
83 fmt.Errorf("user profile not found (subject=`%v`): %w", form.Username, err),
84 http.StatusBadRequest)
85 }
86
87
88 session.Values["reason"] = "10"
89
90 session.Values["iby"] = session.Values["alias"]
91 session.Values["sub"] = userProfile.Alias
92
93 session.Values["ebc-rls"] = userProfile.Roles
94
95 if userProfile.Alias == "" {
96 err := emergency.profileStorage.AddAliasToProfile(c, userProfile)
97 if err != nil {
98 return apperror.NewAbortError(
99 fmt.Errorf("failed to add alias to profile: %w", err),
100 http.StatusInternalServerError)
101 }
102 }
103 }
104
105 continuation := uuid.New().String()
106 session.Values["continuation"] = continuation
107
108 err := session.Save(c.Request, c.Writer)
109 if err != nil {
110 return apperror.NewAbortError(
111 fmt.Errorf("failed to save cookie session: %w", err),
112 http.StatusInternalServerError)
113 }
114
115 return util.WriteJSON(c.Writer, http.StatusOK, gin.H{
116 "challenge": continuation,
117 })
118 }
119
View as plain text