You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
110 lines
2.9 KiB
110 lines
2.9 KiB
|
2 months ago
|
package externalauth
|
||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"crypto/md5"
|
||
|
|
"encoding/binary"
|
||
|
|
"io"
|
||
|
|
"net"
|
||
|
|
"testing"
|
||
|
|
"time"
|
||
|
|
)
|
||
|
|
|
||
|
|
func TestRadiusAccessAcceptVerifiesResponseAuthenticator(t *testing.T) {
|
||
|
|
server, err := net.ListenPacket("udp", "127.0.0.1:0")
|
||
|
|
if err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
defer server.Close()
|
||
|
|
secret := "radius-shared-secret"
|
||
|
|
done := make(chan error, 1)
|
||
|
|
go func() {
|
||
|
|
buffer := make([]byte, 4096)
|
||
|
|
n, address, err := server.ReadFrom(buffer)
|
||
|
|
if err != nil {
|
||
|
|
done <- err
|
||
|
|
return
|
||
|
|
}
|
||
|
|
request := buffer[:n]
|
||
|
|
response := make([]byte, 20)
|
||
|
|
response[0], response[1] = 2, request[1]
|
||
|
|
binary.BigEndian.PutUint16(response[2:4], 20)
|
||
|
|
copy(response[4:20], request[4:20])
|
||
|
|
input := append(append([]byte(nil), response...), []byte(secret)...)
|
||
|
|
digest := md5.Sum(input)
|
||
|
|
copy(response[4:20], digest[:])
|
||
|
|
_, err = server.WriteTo(response, address)
|
||
|
|
done <- err
|
||
|
|
}()
|
||
|
|
port := server.LocalAddr().(*net.UDPAddr).Port
|
||
|
|
accepted, err := (Client{}).Authenticate(context.Background(), "radius", Server{Host: "127.0.0.1", Port: port, Secret: secret}, "operator", "password-1", 2*time.Second)
|
||
|
|
if err != nil || !accepted {
|
||
|
|
t.Fatalf("accepted=%v err=%v", accepted, err)
|
||
|
|
}
|
||
|
|
if err := <-done; err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestTACACSASCIIChallengeFlow(t *testing.T) {
|
||
|
|
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
||
|
|
if err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
defer listener.Close()
|
||
|
|
secret := []byte("tacacs-shared-secret")
|
||
|
|
done := make(chan error, 1)
|
||
|
|
go func() {
|
||
|
|
conn, err := listener.Accept()
|
||
|
|
if err != nil {
|
||
|
|
done <- err
|
||
|
|
return
|
||
|
|
}
|
||
|
|
defer conn.Close()
|
||
|
|
header := make([]byte, 12)
|
||
|
|
if _, err = io.ReadFull(conn, header); err != nil {
|
||
|
|
done <- err
|
||
|
|
return
|
||
|
|
}
|
||
|
|
body := make([]byte, binary.BigEndian.Uint32(header[8:12]))
|
||
|
|
if _, err = io.ReadFull(conn, body); err != nil {
|
||
|
|
done <- err
|
||
|
|
return
|
||
|
|
}
|
||
|
|
body = tacacsXOR(header, secret, body)
|
||
|
|
sessionID := binary.BigEndian.Uint32(header[4:8])
|
||
|
|
if string(body[8:]) != "operator" {
|
||
|
|
done <- io.ErrUnexpectedEOF
|
||
|
|
return
|
||
|
|
}
|
||
|
|
reply := []byte{5, 1, 0, 0, 0, 0}
|
||
|
|
if err = writeTacacsPacket(conn, sessionID, 2, secret, reply); err != nil {
|
||
|
|
done <- err
|
||
|
|
return
|
||
|
|
}
|
||
|
|
if _, err = io.ReadFull(conn, header); err != nil {
|
||
|
|
done <- err
|
||
|
|
return
|
||
|
|
}
|
||
|
|
body = make([]byte, binary.BigEndian.Uint32(header[8:12]))
|
||
|
|
if _, err = io.ReadFull(conn, body); err != nil {
|
||
|
|
done <- err
|
||
|
|
return
|
||
|
|
}
|
||
|
|
body = tacacsXOR(header, secret, body)
|
||
|
|
if string(body[5:]) != "password-1" {
|
||
|
|
done <- io.ErrUnexpectedEOF
|
||
|
|
return
|
||
|
|
}
|
||
|
|
done <- writeTacacsPacket(conn, sessionID, 4, secret, []byte{1, 0, 0, 0, 0, 0})
|
||
|
|
}()
|
||
|
|
port := listener.Addr().(*net.TCPAddr).Port
|
||
|
|
accepted, err := (Client{}).Authenticate(context.Background(), "tacacs", Server{Host: "127.0.0.1", Port: port, Secret: string(secret)}, "operator", "password-1", 2*time.Second)
|
||
|
|
if err != nil || !accepted {
|
||
|
|
t.Fatalf("accepted=%v err=%v", accepted, err)
|
||
|
|
}
|
||
|
|
if err := <-done; err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
}
|