1 package profile
2
3 import (
4 "encoding/json"
5 "fmt"
6 "io"
7 "net"
8 "net/http"
9 "time"
10
11 "edge-infra.dev/pkg/edge/iam/config"
12 "edge-infra.dev/pkg/edge/iam/util"
13 )
14
15 type Profile struct {
16 Subject string `json:"sub"`
17 Organization string `json:"org"`
18
19 Roles string `json:"rls"`
20 GivenName string `json:"given_name,omitempty"`
21 FamilyName string `json:"family_name,omitempty"`
22 FullName string `json:"name,omitempty"`
23 Email string `json:"email,omitempty"`
24 Address *AddressClaim `json:"address,omitempty"`
25 LastUpdated int64 `json:"last_updated"`
26 Alias string `json:"alias"`
27 DeviceLogin string `json:"device_login,omitempty"`
28 Age int `json:"age,omitempty"`
29 }
30
31 type Address struct {
32 City string `json:"city,omitempty"`
33 Country string `json:"country,omitempty"`
34 Street string `json:"street,omitempty"`
35 State string `json:"state,omitempty"`
36 PostalCode string `json:"postalCode,omitempty"`
37 }
38 type ProvisioningUserProfileResponse struct {
39 GivenName string `json:"givenName,omitempty"`
40 FamilyName string `json:"familyName,omitempty"`
41 FullName string `json:"fullName,omitempty"`
42 Email string `json:"email,omitempty"`
43 Address *Address `json:"address,omitempty"`
44 }
45
46 func (p *Profile) RequireVerification(isOffline bool) (bool, error) {
47 lastUpdated := time.Unix(p.LastUpdated, 0)
48 duration := time.Since(lastUpdated)
49
50
51 if duration < config.GetProfileLifespan() {
52 return false, nil
53 }
54
55
56 if isOffline {
57 return false, nil
58 }
59
60
61 client := &http.Client{
62 Timeout: config.CloudIDPTimeout(),
63 }
64
65 url := config.BslSecurityURL()
66 if config.OktaEnabled() {
67 url = config.OktaIssuer()
68 }
69 resp, err := client.Get(url)
70
71
72 if _, ok := err.(net.Error); ok {
73 return false, nil
74 }
75
76
77 if err != nil {
78 return true, err
79 }
80
81 defer resp.Body.Close()
82
83 return true, nil
84 }
85
86
87 func GetUserProfile(accessToken string) (*ProvisioningUserProfileResponse, error) {
88 url := config.ProvisioningUserProfilesURL()
89
90 req, err := http.NewRequest("GET", url, nil)
91 if err != nil {
92 return nil, err
93 }
94
95
96 req.Header.Set("nep-organization", config.OrganizationName())
97 req.Header.Set("Authorization", "AccessToken "+accessToken)
98
99 client := &http.Client{}
100 resp, err := client.Do(req)
101 if err != nil {
102 return nil, err
103 }
104
105 defer resp.Body.Close()
106
107 if resp.StatusCode != http.StatusOK {
108 respBody, err := io.ReadAll(resp.Body)
109 if err != nil {
110 return nil, fmt.Errorf("failed to read user profile response body. %s", err.Error())
111 }
112 return nil, fmt.Errorf("failed to get user profile. response body: %s", string(respBody))
113 }
114
115 body, err := io.ReadAll(resp.Body)
116 if err != nil {
117 return nil, err
118 }
119
120 var userProfileResponse ProvisioningUserProfileResponse
121 err = json.Unmarshal(body, &userProfileResponse)
122 if err != nil {
123 return nil, err
124 }
125
126 return &userProfileResponse, nil
127 }
128
129
130
131
132
133 func GetRoles(nepOrg string, envURL string, accessToken string) (string, error) {
134 url := envURL
135 req, err := http.NewRequest("GET", url, nil)
136 if err != nil {
137 return "", err
138 }
139
140
141 req.Header.Set("Authorization", "AccessToken "+accessToken)
142 req.Header.Set("nep-organization", nepOrg)
143
144 client := &http.Client{}
145 resp, err := client.Do(req)
146 if err != nil {
147 return "", err
148 }
149
150 defer resp.Body.Close()
151
152
153 if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
154 respBody, err := io.ReadAll(resp.Body)
155 if err != nil {
156 return "", fmt.Errorf("Unexpected status code: %d. Error reading response body: %s", resp.StatusCode, err.Error())
157 }
158 return "", fmt.Errorf("Unexpected status code: %d. Response body: %s", resp.StatusCode, string(respBody))
159 }
160
161 body, err := io.ReadAll(resp.Body)
162 if err != nil {
163 return "", err
164 }
165
166 var data map[string]interface{}
167 err = json.Unmarshal(body, &data)
168 if err != nil {
169 return "", err
170 }
171
172
173 grantedRoles, ok := data["grantedRoles"].([]interface{})
174 if !ok {
175 return "", err
176 }
177
178
179 output := []string{}
180 for _, item := range grantedRoles {
181 roleName, ok := item.(map[string]interface{})["roleName"].(string)
182 if ok {
183 output = append(output, roleName)
184 }
185 }
186
187
188 roles, err := util.Serialize(output)
189 if err != nil {
190 return "", err
191 }
192
193 return roles, nil
194 }
195
View as plain text