github.com/jcmturner/gokrb5/v8@v8.4.4/service/APExchange_test.go (about) 1 package service 2 3 import ( 4 "encoding/hex" 5 "strings" 6 "testing" 7 "time" 8 9 "github.com/jcmturner/gokrb5/v8/client" 10 "github.com/jcmturner/gokrb5/v8/config" 11 "github.com/jcmturner/gokrb5/v8/credentials" 12 "github.com/jcmturner/gokrb5/v8/iana/errorcode" 13 "github.com/jcmturner/gokrb5/v8/iana/flags" 14 "github.com/jcmturner/gokrb5/v8/iana/nametype" 15 "github.com/jcmturner/gokrb5/v8/keytab" 16 "github.com/jcmturner/gokrb5/v8/messages" 17 "github.com/jcmturner/gokrb5/v8/test/testdata" 18 "github.com/jcmturner/gokrb5/v8/types" 19 "github.com/stretchr/testify/assert" 20 ) 21 22 func TestVerifyAPREQ(t *testing.T) { 23 t.Parallel() 24 cl := getClient() 25 sname := types.PrincipalName{ 26 NameType: nametype.KRB_NT_PRINCIPAL, 27 NameString: []string{"HTTP", "host.test.gokrb5"}, 28 } 29 b, _ := hex.DecodeString(testdata.HTTP_KEYTAB) 30 kt := keytab.New() 31 kt.Unmarshal(b) 32 st := time.Now().UTC() 33 tkt, sessionKey, err := messages.NewTicket(cl.Credentials.CName(), cl.Credentials.Domain(), 34 sname, "TEST.GOKRB5", 35 types.NewKrbFlags(), 36 kt, 37 18, 38 1, 39 st, 40 st, 41 st.Add(time.Duration(24)*time.Hour), 42 st.Add(time.Duration(48)*time.Hour), 43 ) 44 if err != nil { 45 t.Fatalf("Error getting test ticket: %v", err) 46 } 47 APReq, err := messages.NewAPReq( 48 tkt, 49 sessionKey, 50 newTestAuthenticator(*cl.Credentials), 51 ) 52 if err != nil { 53 t.Fatalf("Error getting test AP_REQ: %v", err) 54 } 55 56 h, _ := types.GetHostAddress("127.0.0.1:1234") 57 s := NewSettings(kt, ClientAddress(h)) 58 ok, _, err := VerifyAPREQ(&APReq, s) 59 if !ok || err != nil { 60 t.Fatalf("Validation of AP_REQ failed when it should not have: %v", err) 61 } 62 } 63 64 func TestVerifyAPREQWithPrincipalOverride(t *testing.T) { 65 t.Parallel() 66 cl := getClient() 67 sname := types.PrincipalName{ 68 NameType: nametype.KRB_NT_PRINCIPAL, 69 NameString: []string{"HTTP", "host.test.gokrb5"}, 70 } 71 b, _ := hex.DecodeString(testdata.HTTP_KEYTAB) 72 kt := keytab.New() 73 kt.Unmarshal(b) 74 st := time.Now().UTC() 75 tkt, sessionKey, err := messages.NewTicket(cl.Credentials.CName(), cl.Credentials.Domain(), 76 sname, "TEST.GOKRB5", 77 types.NewKrbFlags(), 78 kt, 79 18, 80 1, 81 st, 82 st, 83 st.Add(time.Duration(24)*time.Hour), 84 st.Add(time.Duration(48)*time.Hour), 85 ) 86 if err != nil { 87 t.Fatalf("Error getting test ticket: %v", err) 88 } 89 apReq, err := messages.NewAPReq( 90 tkt, 91 sessionKey, 92 newTestAuthenticator(*cl.Credentials), 93 ) 94 if err != nil { 95 t.Fatalf("Error getting test AP_REQ: %v", err) 96 } 97 98 h, _ := types.GetHostAddress("127.0.0.1:1234") 99 s := NewSettings(kt, ClientAddress(h), KeytabPrincipal("foo")) 100 ok, _, err := VerifyAPREQ(&apReq, s) 101 if ok || err == nil { 102 t.Fatalf("Validation of AP_REQ should have failed") 103 } 104 if !strings.Contains(err.Error(), "Looking for \"foo\" realm") { 105 t.Fatalf("Looking for wrong entity: %s", err.Error()) 106 } 107 } 108 109 func TestVerifyAPREQ_KRB_AP_ERR_BADMATCH(t *testing.T) { 110 t.Parallel() 111 cl := getClient() 112 sname := types.PrincipalName{ 113 NameType: nametype.KRB_NT_PRINCIPAL, 114 NameString: []string{"HTTP", "host.test.gokrb5"}, 115 } 116 b, _ := hex.DecodeString(testdata.HTTP_KEYTAB) 117 kt := keytab.New() 118 kt.Unmarshal(b) 119 st := time.Now().UTC() 120 tkt, sessionKey, err := messages.NewTicket(cl.Credentials.CName(), cl.Credentials.Domain(), 121 sname, "TEST.GOKRB5", 122 types.NewKrbFlags(), 123 kt, 124 18, 125 1, 126 st, 127 st, 128 st.Add(time.Duration(24)*time.Hour), 129 st.Add(time.Duration(48)*time.Hour), 130 ) 131 if err != nil { 132 t.Fatalf("Error getting test ticket: %v", err) 133 } 134 a := newTestAuthenticator(*cl.Credentials) 135 a.CName = types.PrincipalName{ 136 NameType: nametype.KRB_NT_PRINCIPAL, 137 NameString: []string{"BADMATCH"}, 138 } 139 APReq, err := messages.NewAPReq( 140 tkt, 141 sessionKey, 142 a, 143 ) 144 if err != nil { 145 t.Fatalf("Error getting test AP_REQ: %v", err) 146 } 147 h, _ := types.GetHostAddress("127.0.0.1:1234") 148 s := NewSettings(kt, ClientAddress(h)) 149 ok, _, err := VerifyAPREQ(&APReq, s) 150 if ok || err == nil { 151 t.Fatal("Validation of AP_REQ passed when it should not have") 152 } 153 if _, ok := err.(messages.KRBError); ok { 154 assert.Equal(t, errorcode.KRB_AP_ERR_BADMATCH, err.(messages.KRBError).ErrorCode, "Error code not as expected") 155 } else { 156 t.Fatalf("Error is not a KRBError: %v", err) 157 } 158 } 159 160 func TestVerifyAPREQ_LargeClockSkew(t *testing.T) { 161 t.Parallel() 162 cl := getClient() 163 sname := types.PrincipalName{ 164 NameType: nametype.KRB_NT_PRINCIPAL, 165 NameString: []string{"HTTP", "host.test.gokrb5"}, 166 } 167 b, _ := hex.DecodeString(testdata.HTTP_KEYTAB) 168 kt := keytab.New() 169 kt.Unmarshal(b) 170 st := time.Now().UTC() 171 tkt, sessionKey, err := messages.NewTicket(cl.Credentials.CName(), cl.Credentials.Domain(), 172 sname, "TEST.GOKRB5", 173 types.NewKrbFlags(), 174 kt, 175 18, 176 1, 177 st, 178 st, 179 st.Add(time.Duration(24)*time.Hour), 180 st.Add(time.Duration(48)*time.Hour), 181 ) 182 if err != nil { 183 t.Fatalf("Error getting test ticket: %v", err) 184 } 185 a := newTestAuthenticator(*cl.Credentials) 186 a.CTime = a.CTime.Add(time.Duration(-10) * time.Minute) 187 APReq, err := messages.NewAPReq( 188 tkt, 189 sessionKey, 190 a, 191 ) 192 if err != nil { 193 t.Fatalf("Error getting test AP_REQ: %v", err) 194 } 195 196 h, _ := types.GetHostAddress("127.0.0.1:1234") 197 s := NewSettings(kt, ClientAddress(h)) 198 ok, _, err := VerifyAPREQ(&APReq, s) 199 if ok || err == nil { 200 t.Fatal("Validation of AP_REQ passed when it should not have") 201 } 202 if _, ok := err.(messages.KRBError); ok { 203 assert.Equal(t, errorcode.KRB_AP_ERR_SKEW, err.(messages.KRBError).ErrorCode, "Error code not as expected") 204 } else { 205 t.Fatalf("Error is not a KRBError: %v", err) 206 } 207 } 208 209 func TestVerifyAPREQ_Replay(t *testing.T) { 210 t.Parallel() 211 cl := getClient() 212 sname := types.PrincipalName{ 213 NameType: nametype.KRB_NT_PRINCIPAL, 214 NameString: []string{"HTTP", "host.test.gokrb5"}, 215 } 216 b, _ := hex.DecodeString(testdata.HTTP_KEYTAB) 217 kt := keytab.New() 218 kt.Unmarshal(b) 219 st := time.Now().UTC() 220 tkt, sessionKey, err := messages.NewTicket(cl.Credentials.CName(), cl.Credentials.Domain(), 221 sname, "TEST.GOKRB5", 222 types.NewKrbFlags(), 223 kt, 224 18, 225 1, 226 st, 227 st, 228 st.Add(time.Duration(24)*time.Hour), 229 st.Add(time.Duration(48)*time.Hour), 230 ) 231 if err != nil { 232 t.Fatalf("Error getting test ticket: %v", err) 233 } 234 APReq, err := messages.NewAPReq( 235 tkt, 236 sessionKey, 237 newTestAuthenticator(*cl.Credentials), 238 ) 239 if err != nil { 240 t.Fatalf("Error getting test AP_REQ: %v", err) 241 } 242 243 h, _ := types.GetHostAddress("127.0.0.1:1234") 244 s := NewSettings(kt, ClientAddress(h)) 245 ok, _, err := VerifyAPREQ(&APReq, s) 246 if !ok || err != nil { 247 t.Fatalf("Validation of AP_REQ failed when it should not have: %v", err) 248 } 249 // Replay 250 ok, _, err = VerifyAPREQ(&APReq, s) 251 if ok || err == nil { 252 t.Fatal("Validation of AP_REQ passed when it should not have") 253 } 254 assert.IsType(t, messages.KRBError{}, err, "Error is not a KRBError") 255 assert.Equal(t, errorcode.KRB_AP_ERR_REPEAT, err.(messages.KRBError).ErrorCode, "Error code not as expected") 256 } 257 258 func TestVerifyAPREQ_FutureTicket(t *testing.T) { 259 t.Parallel() 260 cl := getClient() 261 sname := types.PrincipalName{ 262 NameType: nametype.KRB_NT_PRINCIPAL, 263 NameString: []string{"HTTP", "host.test.gokrb5"}, 264 } 265 b, _ := hex.DecodeString(testdata.HTTP_KEYTAB) 266 kt := keytab.New() 267 kt.Unmarshal(b) 268 st := time.Now().UTC() 269 tkt, sessionKey, err := messages.NewTicket(cl.Credentials.CName(), cl.Credentials.Domain(), 270 sname, "TEST.GOKRB5", 271 types.NewKrbFlags(), 272 kt, 273 18, 274 1, 275 st, 276 st.Add(time.Duration(60)*time.Minute), 277 st.Add(time.Duration(24)*time.Hour), 278 st.Add(time.Duration(48)*time.Hour), 279 ) 280 if err != nil { 281 t.Fatalf("Error getting test ticket: %v", err) 282 } 283 a := newTestAuthenticator(*cl.Credentials) 284 APReq, err := messages.NewAPReq( 285 tkt, 286 sessionKey, 287 a, 288 ) 289 if err != nil { 290 t.Fatalf("Error getting test AP_REQ: %v", err) 291 } 292 293 h, _ := types.GetHostAddress("127.0.0.1:1234") 294 s := NewSettings(kt, ClientAddress(h)) 295 ok, _, err := VerifyAPREQ(&APReq, s) 296 if ok || err == nil { 297 t.Fatal("Validation of AP_REQ passed when it should not have") 298 } 299 if _, ok := err.(messages.KRBError); ok { 300 assert.Equal(t, errorcode.KRB_AP_ERR_TKT_NYV, err.(messages.KRBError).ErrorCode, "Error code not as expected") 301 } else { 302 t.Fatalf("Error is not a KRBError: %v", err) 303 } 304 } 305 306 func TestVerifyAPREQ_InvalidTicket(t *testing.T) { 307 t.Parallel() 308 cl := getClient() 309 sname := types.PrincipalName{ 310 NameType: nametype.KRB_NT_PRINCIPAL, 311 NameString: []string{"HTTP", "host.test.gokrb5"}, 312 } 313 b, _ := hex.DecodeString(testdata.HTTP_KEYTAB) 314 kt := keytab.New() 315 kt.Unmarshal(b) 316 st := time.Now().UTC() 317 f := types.NewKrbFlags() 318 types.SetFlag(&f, flags.Invalid) 319 tkt, sessionKey, err := messages.NewTicket(cl.Credentials.CName(), cl.Credentials.Domain(), 320 sname, "TEST.GOKRB5", 321 f, 322 kt, 323 18, 324 1, 325 st, 326 st, 327 st.Add(time.Duration(24)*time.Hour), 328 st.Add(time.Duration(48)*time.Hour), 329 ) 330 if err != nil { 331 t.Fatalf("Error getting test ticket: %v", err) 332 } 333 APReq, err := messages.NewAPReq( 334 tkt, 335 sessionKey, 336 newTestAuthenticator(*cl.Credentials), 337 ) 338 if err != nil { 339 t.Fatalf("Error getting test AP_REQ: %v", err) 340 } 341 342 h, _ := types.GetHostAddress("127.0.0.1:1234") 343 s := NewSettings(kt, ClientAddress(h)) 344 ok, _, err := VerifyAPREQ(&APReq, s) 345 if ok || err == nil { 346 t.Fatal("Validation of AP_REQ passed when it should not have") 347 } 348 if _, ok := err.(messages.KRBError); ok { 349 assert.Equal(t, errorcode.KRB_AP_ERR_TKT_NYV, err.(messages.KRBError).ErrorCode, "Error code not as expected") 350 } else { 351 t.Fatalf("Error is not a KRBError: %v", err) 352 } 353 } 354 355 func TestVerifyAPREQ_ExpiredTicket(t *testing.T) { 356 t.Parallel() 357 cl := getClient() 358 sname := types.PrincipalName{ 359 NameType: nametype.KRB_NT_PRINCIPAL, 360 NameString: []string{"HTTP", "host.test.gokrb5"}, 361 } 362 b, _ := hex.DecodeString(testdata.HTTP_KEYTAB) 363 kt := keytab.New() 364 kt.Unmarshal(b) 365 st := time.Now().UTC() 366 tkt, sessionKey, err := messages.NewTicket(cl.Credentials.CName(), cl.Credentials.Domain(), 367 sname, "TEST.GOKRB5", 368 types.NewKrbFlags(), 369 kt, 370 18, 371 1, 372 st, 373 st, 374 st.Add(time.Duration(-30)*time.Minute), 375 st.Add(time.Duration(48)*time.Hour), 376 ) 377 if err != nil { 378 t.Fatalf("Error getting test ticket: %v", err) 379 } 380 a := newTestAuthenticator(*cl.Credentials) 381 APReq, err := messages.NewAPReq( 382 tkt, 383 sessionKey, 384 a, 385 ) 386 if err != nil { 387 t.Fatalf("Error getting test AP_REQ: %v", err) 388 } 389 390 h, _ := types.GetHostAddress("127.0.0.1:1234") 391 s := NewSettings(kt, ClientAddress(h)) 392 ok, _, err := VerifyAPREQ(&APReq, s) 393 if ok || err == nil { 394 t.Fatal("Validation of AP_REQ passed when it should not have") 395 } 396 if _, ok := err.(messages.KRBError); ok { 397 assert.Equal(t, errorcode.KRB_AP_ERR_TKT_EXPIRED, err.(messages.KRBError).ErrorCode, "Error code not as expected") 398 } else { 399 t.Fatalf("Error is not a KRBError: %v", err) 400 } 401 } 402 403 func newTestAuthenticator(creds credentials.Credentials) types.Authenticator { 404 auth, _ := types.NewAuthenticator(creds.Domain(), creds.CName()) 405 auth.GenerateSeqNumberAndSubKey(18, 32) 406 //auth.Cksum = types.Checksum{ 407 // CksumType: chksumtype.GSSAPI, 408 // Checksum: newAuthenticatorChksum([]int{GSS_C_INTEG_FLAG, GSS_C_CONF_FLAG}), 409 //} 410 return auth 411 } 412 413 func getClient() *client.Client { 414 b, _ := hex.DecodeString(testdata.KEYTAB_TESTUSER1_TEST_GOKRB5) 415 kt := keytab.New() 416 kt.Unmarshal(b) 417 c, _ := config.NewFromString(testdata.KRB5_CONF) 418 cl := client.NewWithKeytab("testuser1", "TEST.GOKRB5", kt, c) 419 return cl 420 }