github.com/volatiletech/authboss@v2.4.1+incompatible/events.go (about)

     1  package authboss
     2  
     3  import (
     4  	"net/http"
     5  )
     6  
     7  //go:generate stringer -output stringers.go -type "Event"
     8  
     9  // Event type is for describing events
    10  type Event int
    11  
    12  // Event kinds
    13  const (
    14  	EventRegister Event = iota
    15  	EventAuth
    16  	// EventAuthHijack is used to steal the authentication process after a
    17  	// successful auth but before any session variable has been put in.
    18  	// Most useful for defining an additional step for authentication
    19  	// (like 2fa). It needs to be separate to EventAuth because other modules
    20  	// do checks that would also interrupt event handlers with an authentication
    21  	// failure so there's an ordering problem.
    22  	EventAuthHijack
    23  	EventOAuth2
    24  	EventAuthFail
    25  	EventOAuth2Fail
    26  	EventRecoverStart
    27  	EventRecoverEnd
    28  	EventGetUser
    29  	EventGetUserSession
    30  	EventPasswordReset
    31  	EventLogout
    32  )
    33  
    34  // EventHandler reacts to events that are fired by Authboss controllers.
    35  // These controllers will normally process a request by themselves, but if
    36  // there is special consideration for example a successful login, but the
    37  // user is locked, the lock module's controller may seize control over the
    38  // request.
    39  //
    40  // Very much a controller level middleware.
    41  type EventHandler func(w http.ResponseWriter, r *http.Request, handled bool) (bool, error)
    42  
    43  // Events is a collection of Events that fire before and after certain methods.
    44  type Events struct {
    45  	before map[Event][]EventHandler
    46  	after  map[Event][]EventHandler
    47  }
    48  
    49  // NewEvents creates a new set of before and after Events.
    50  func NewEvents() *Events {
    51  	return &Events{
    52  		before: make(map[Event][]EventHandler),
    53  		after:  make(map[Event][]EventHandler),
    54  	}
    55  }
    56  
    57  // Before event, call f.
    58  func (c *Events) Before(e Event, f EventHandler) {
    59  	events := c.before[e]
    60  	events = append(events, f)
    61  	c.before[e] = events
    62  }
    63  
    64  // After event, call f.
    65  func (c *Events) After(e Event, f EventHandler) {
    66  	events := c.after[e]
    67  	events = append(events, f)
    68  	c.after[e] = events
    69  }
    70  
    71  // FireBefore executes the handlers that were registered to fire before
    72  // the event passed in.
    73  //
    74  // If it encounters an error it will stop immediately without calling
    75  // other handlers.
    76  //
    77  // If a handler handles the request, it will pass this information both
    78  // to handlers further down the chain (to let them know that w has been used)
    79  // as well as set w to nil as a precaution.
    80  func (c *Events) FireBefore(e Event, w http.ResponseWriter, r *http.Request) (bool, error) {
    81  	return c.call(c.before[e], w, r)
    82  }
    83  
    84  // FireAfter event to all the Events with a context. The error can safely be
    85  // ignored as it is logged.
    86  func (c *Events) FireAfter(e Event, w http.ResponseWriter, r *http.Request) (bool, error) {
    87  	return c.call(c.after[e], w, r)
    88  }
    89  
    90  func (c *Events) call(evs []EventHandler, w http.ResponseWriter, r *http.Request) (bool, error) {
    91  	handled := false
    92  
    93  	for _, fn := range evs {
    94  		interrupt, err := fn(w, r, handled)
    95  		if err != nil {
    96  			return false, err
    97  		}
    98  		if interrupt {
    99  			handled = true
   100  		}
   101  	}
   102  
   103  	return handled, nil
   104  }