github.com/jcmturner/gokrb5/v8@v8.4.4/examples/example-AD.go (about) 1 //go:build examples 2 // +build examples 3 4 package main 5 6 import ( 7 "encoding/hex" 8 "errors" 9 "fmt" 10 "io" 11 "log" 12 "net/http" 13 "net/http/httptest" 14 "os" 15 16 "github.com/gorilla/sessions" 17 "github.com/jcmturner/goidentity/v6" 18 "github.com/jcmturner/gokrb5/v8/client" 19 "github.com/jcmturner/gokrb5/v8/config" 20 "github.com/jcmturner/gokrb5/v8/credentials" 21 "github.com/jcmturner/gokrb5/v8/keytab" 22 "github.com/jcmturner/gokrb5/v8/service" 23 "github.com/jcmturner/gokrb5/v8/spnego" 24 "github.com/jcmturner/gokrb5/v8/test/testdata" 25 ) 26 27 func main() { 28 s := httpServer() 29 defer s.Close() 30 fmt.Printf("Listening on %s\n", s.URL) 31 l := log.New(os.Stderr, "GOKRB5 Client: ", log.Ldate|log.Ltime|log.Lshortfile) 32 33 b, _ := hex.DecodeString(testdata.KEYTAB_TESTUSER1_USER_GOKRB5) 34 kt := keytab.New() 35 kt.Unmarshal(b) 36 c, _ := config.NewFromString(testdata.KRB5_CONF) 37 cl := client.NewWithKeytab("testuser1", "USER.GOKRB5", kt, c, client.DisablePAFXFAST(true), client.Logger(l)) 38 httpRequest(s.URL, cl) 39 40 b, _ = hex.DecodeString(testdata.KEYTAB_TESTUSER2_USER_GOKRB5) 41 kt = keytab.New() 42 kt.Unmarshal(b) 43 c, _ = config.NewFromString(testdata.KRB5_CONF) 44 cl = client.NewWithKeytab("testuser2", "USER.GOKRB5", kt, c, client.DisablePAFXFAST(true), client.Logger(l)) 45 httpRequest(s.URL, cl) 46 } 47 48 func httpRequest(url string, cl *client.Client) { 49 l := log.New(os.Stderr, "GOKRB5 Client: ", log.Ldate|log.Ltime|log.Lshortfile) 50 51 err := cl.Login() 52 if err != nil { 53 l.Fatalf("Error on AS_REQ: %v\n", err) 54 } 55 56 spnegoCl := spnego.NewClient(cl, nil, "HTTP/host.res.gokrb5") 57 58 // Make the request for the first time with no session 59 r, _ := http.NewRequest("GET", url, nil) 60 httpResp, err := spnegoCl.Do(r) 61 if err != nil { 62 l.Fatalf("error making request: %v", err) 63 } 64 fmt.Fprintf(os.Stdout, "Response Code: %v\n", httpResp.StatusCode) 65 content, _ := io.ReadAll(httpResp.Body) 66 fmt.Fprintf(os.Stdout, "Response Body:\n%s\n", content) 67 68 // Make the request again which should use the session 69 httpResp, err = spnegoCl.Do(r) 70 if err != nil { 71 l.Fatalf("error making request: %v", err) 72 } 73 fmt.Fprintf(os.Stdout, "Response Code: %v\n", httpResp.StatusCode) 74 content, _ = io.ReadAll(httpResp.Body) 75 fmt.Fprintf(os.Stdout, "Response Body:\n%s\n", content) 76 } 77 78 func httpServer() *httptest.Server { 79 l := log.New(os.Stderr, "GOKRB5 Service Tests: ", log.Ldate|log.Ltime|log.Lshortfile) 80 b, _ := hex.DecodeString(testdata.KEYTAB_SYSHTTP_RES_GOKRB5) 81 kt := keytab.New() 82 kt.Unmarshal(b) 83 th := http.HandlerFunc(testAppHandler) 84 s := httptest.NewServer(spnego.SPNEGOKRB5Authenticate(th, kt, service.Logger(l), service.KeytabPrincipal("sysHTTP"), service.SessionManager(NewSessionMgr("gokrb5")))) 85 return s 86 } 87 88 func testAppHandler(w http.ResponseWriter, r *http.Request) { 89 creds := goidentity.FromHTTPRequestContext(r) 90 fmt.Fprint(w, "<html>\n<p><h1>GOKRB5 Handler</h1></p>\n") 91 if creds != nil && creds.Authenticated() { 92 fmt.Fprintf(w, "<ul><li>Authenticed user: %s</li>\n", creds.UserName()) 93 fmt.Fprintf(w, "<li>User's realm: %s</li>\n", creds.Domain()) 94 fmt.Fprint(w, "<li>Authz Attributes (Group Memberships):</li><ul>\n") 95 for _, s := range creds.AuthzAttributes() { 96 fmt.Fprintf(w, "<li>%v</li>\n", s) 97 } 98 fmt.Fprint(w, "</ul>\n") 99 if ADCredsJSON, ok := creds.Attributes()[credentials.AttributeKeyADCredentials]; ok { 100 //ADCreds := new(credentials.ADCredentials) 101 ADCreds := ADCredsJSON.(credentials.ADCredentials) 102 //err := json.Unmarshal(aj, ADCreds) 103 //if err == nil { 104 // Now access the fields of the ADCredentials struct. For example: 105 fmt.Fprintf(w, "<li>EffectiveName: %v</li>\n", ADCreds.EffectiveName) 106 fmt.Fprintf(w, "<li>FullName: %v</li>\n", ADCreds.FullName) 107 fmt.Fprintf(w, "<li>UserID: %v</li>\n", ADCreds.UserID) 108 fmt.Fprintf(w, "<li>PrimaryGroupID: %v</li>\n", ADCreds.PrimaryGroupID) 109 fmt.Fprintf(w, "<li>Group SIDs: %v</li>\n", ADCreds.GroupMembershipSIDs) 110 fmt.Fprintf(w, "<li>LogOnTime: %v</li>\n", ADCreds.LogOnTime) 111 fmt.Fprintf(w, "<li>LogOffTime: %v</li>\n", ADCreds.LogOffTime) 112 fmt.Fprintf(w, "<li>PasswordLastSet: %v</li>\n", ADCreds.PasswordLastSet) 113 fmt.Fprintf(w, "<li>LogonServer: %v</li>\n", ADCreds.LogonServer) 114 fmt.Fprintf(w, "<li>LogonDomainName: %v</li>\n", ADCreds.LogonDomainName) 115 fmt.Fprintf(w, "<li>LogonDomainID: %v</li>\n", ADCreds.LogonDomainID) 116 //} 117 } 118 fmt.Fprint(w, "</ul>") 119 } else { 120 w.WriteHeader(http.StatusUnauthorized) 121 fmt.Fprint(w, "Authentication failed") 122 } 123 fmt.Fprint(w, "</html>") 124 return 125 } 126 127 type SessionMgr struct { 128 skey []byte 129 store sessions.Store 130 cookieName string 131 } 132 133 func NewSessionMgr(cookieName string) SessionMgr { 134 skey := []byte("thisistestsecret") // Best practice is to load this key from a secure location. 135 return SessionMgr{ 136 skey: skey, 137 store: sessions.NewCookieStore(skey), 138 cookieName: cookieName, 139 } 140 } 141 142 func (smgr SessionMgr) Get(r *http.Request, k string) ([]byte, error) { 143 s, err := smgr.store.Get(r, smgr.cookieName) 144 if err != nil { 145 return nil, err 146 } 147 if s == nil { 148 return nil, errors.New("nil session") 149 } 150 b, ok := s.Values[k].([]byte) 151 if !ok { 152 return nil, fmt.Errorf("could not get bytes held in session at %s", k) 153 } 154 return b, nil 155 } 156 157 func (smgr SessionMgr) New(w http.ResponseWriter, r *http.Request, k string, v []byte) error { 158 s, err := smgr.store.New(r, smgr.cookieName) 159 if err != nil { 160 return fmt.Errorf("could not get new session from session manager: %v", err) 161 } 162 s.Values[k] = v 163 return s.Save(r, w) 164 }