package ldap import ( "sync" ldap "github.com/vjeantet/ldapserver" ) // connection is the part of the underlying server's client type that // this bridge uses for state belonging to a connection rather than to // a single request. That type is unexported, so it is reached through // the message and abstracted here so tests can supply their own. type connection interface { GetData() interface{} SetData(interface{}) } // boundState is the per-connection record stored in the client's // additional data, which releases it together with the connection. type boundState struct { sync.Mutex bound bool } // messageConn returns the connection a request arrived on. func messageConn(m *ldap.Message) connection { if m == nil || m.Client == nil { return nil } return m.Client } // connOf returns the connection for a request. It is a field so that // tests can inject a connection without the server's unexported // client type. func (s *server) connOf(m *ldap.Message) connection { if s.conn == nil { return messageConn(m) } return s.conn(m) } // bound reports whether the request arrived on a connection that has // already been authenticated. func (s *server) bound(m *ldap.Message) bool { st := existingState(s.connOf(m)) if st == nil { return false } st.Lock() defer st.Unlock() return st.bound } // markBound records that the connection has been authenticated. func (s *server) markBound(m *ldap.Message) { c := s.connOf(m) if c == nil { return } if st := existingState(c); st != nil { st.Lock() defer st.Unlock() st.bound = true return } c.SetData(&boundState{bound: true}) } // markUnbound clears the authentication state of a connection. RFC // 4511 requires a failed bind to leave the connection unauthenticated // so that a client cannot hold on to access it has lost. func (s *server) markUnbound(m *ldap.Message) { st := existingState(s.connOf(m)) if st == nil { return } st.Lock() defer st.Unlock() st.bound = false } func existingState(c connection) *boundState { if c == nil { return nil } st, _ := c.GetData().(*boundState) return st }