github.com/levb/mattermost-server@v5.3.1+incompatible/web/saml.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See License.txt for license information.
     3  
     4  package web
     5  
     6  import (
     7  	b64 "encoding/base64"
     8  	"net/http"
     9  	"strings"
    10  
    11  	"github.com/mattermost/mattermost-server/mlog"
    12  	"github.com/mattermost/mattermost-server/model"
    13  )
    14  
    15  func (w *Web) InitSaml() {
    16  	w.MainRouter.Handle("/login/sso/saml", w.NewHandler(loginWithSaml)).Methods("GET")
    17  	w.MainRouter.Handle("/login/sso/saml", w.NewHandler(completeSaml)).Methods("POST")
    18  }
    19  
    20  func loginWithSaml(c *Context, w http.ResponseWriter, r *http.Request) {
    21  	samlInterface := c.App.Saml
    22  
    23  	if samlInterface == nil {
    24  		c.Err = model.NewAppError("loginWithSaml", "api.user.saml.not_available.app_error", nil, "", http.StatusFound)
    25  		return
    26  	}
    27  
    28  	teamId, err := c.App.GetTeamIdFromQuery(r.URL.Query())
    29  	if err != nil {
    30  		c.Err = err
    31  		return
    32  	}
    33  	action := r.URL.Query().Get("action")
    34  	redirectTo := r.URL.Query().Get("redirect_to")
    35  	extensionId := r.URL.Query().Get("extension_id")
    36  	relayProps := map[string]string{}
    37  	relayState := ""
    38  
    39  	if len(action) != 0 {
    40  		relayProps["team_id"] = teamId
    41  		relayProps["action"] = action
    42  		if action == model.OAUTH_ACTION_EMAIL_TO_SSO {
    43  			relayProps["email"] = r.URL.Query().Get("email")
    44  		}
    45  	}
    46  
    47  	if len(redirectTo) != 0 {
    48  		relayProps["redirect_to"] = redirectTo
    49  	}
    50  
    51  	if len(extensionId) != 0 {
    52  		relayProps["extension_id"] = extensionId
    53  		err := c.App.ValidateExtension(extensionId)
    54  		if err != nil {
    55  			c.Err = err
    56  			return
    57  		}
    58  	}
    59  
    60  	if len(relayProps) > 0 {
    61  		relayState = b64.StdEncoding.EncodeToString([]byte(model.MapToJson(relayProps)))
    62  	}
    63  
    64  	if data, err := samlInterface.BuildRequest(relayState); err != nil {
    65  		c.Err = err
    66  		return
    67  	} else {
    68  		w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
    69  		http.Redirect(w, r, data.URL, http.StatusFound)
    70  	}
    71  }
    72  
    73  func completeSaml(c *Context, w http.ResponseWriter, r *http.Request) {
    74  	samlInterface := c.App.Saml
    75  
    76  	if samlInterface == nil {
    77  		c.Err = model.NewAppError("completeSaml", "api.user.saml.not_available.app_error", nil, "", http.StatusFound)
    78  		return
    79  	}
    80  
    81  	//Validate that the user is with SAML and all that
    82  	encodedXML := r.FormValue("SAMLResponse")
    83  	relayState := r.FormValue("RelayState")
    84  
    85  	relayProps := make(map[string]string)
    86  	if len(relayState) > 0 {
    87  		stateStr := ""
    88  		if b, err := b64.StdEncoding.DecodeString(relayState); err != nil {
    89  			c.Err = model.NewAppError("completeSaml", "api.user.authorize_oauth_user.invalid_state.app_error", nil, err.Error(), http.StatusFound)
    90  			return
    91  		} else {
    92  			stateStr = string(b)
    93  		}
    94  		relayProps = model.MapFromJson(strings.NewReader(stateStr))
    95  	}
    96  
    97  	action := relayProps["action"]
    98  	if user, err := samlInterface.DoLogin(encodedXML, relayProps); err != nil {
    99  		if action == model.OAUTH_ACTION_MOBILE {
   100  			err.Translate(c.T)
   101  			w.Write([]byte(err.ToJson()))
   102  		} else {
   103  			c.Err = err
   104  			c.Err.StatusCode = http.StatusFound
   105  		}
   106  		return
   107  	} else {
   108  		if err := c.App.CheckUserAllAuthenticationCriteria(user, ""); err != nil {
   109  			c.Err = err
   110  			c.Err.StatusCode = http.StatusFound
   111  			return
   112  		}
   113  
   114  		switch action {
   115  		case model.OAUTH_ACTION_SIGNUP:
   116  			teamId := relayProps["team_id"]
   117  			if len(teamId) > 0 {
   118  				c.App.Go(func() {
   119  					if err := c.App.AddUserToTeamByTeamId(teamId, user); err != nil {
   120  						mlog.Error(err.Error())
   121  					} else {
   122  						c.App.AddDirectChannels(teamId, user)
   123  					}
   124  				})
   125  			}
   126  		case model.OAUTH_ACTION_EMAIL_TO_SSO:
   127  			if err := c.App.RevokeAllSessions(user.Id); err != nil {
   128  				c.Err = err
   129  				return
   130  			}
   131  			c.LogAuditWithUserId(user.Id, "Revoked all sessions for user")
   132  			c.App.Go(func() {
   133  				if err := c.App.SendSignInChangeEmail(user.Email, strings.Title(model.USER_AUTH_SERVICE_SAML)+" SSO", user.Locale, c.App.GetSiteURL()); err != nil {
   134  					mlog.Error(err.Error())
   135  				}
   136  			})
   137  		}
   138  
   139  		session, err := c.App.DoLogin(w, r, user, "")
   140  		if err != nil {
   141  			c.Err = err
   142  			return
   143  		}
   144  
   145  		c.Session = *session
   146  
   147  		if val, ok := relayProps["redirect_to"]; ok {
   148  			http.Redirect(w, r, c.GetSiteURLHeader()+val, http.StatusFound)
   149  			return
   150  		}
   151  
   152  		if action == model.OAUTH_ACTION_MOBILE {
   153  			ReturnStatusOK(w)
   154  		} else if action == model.OAUTH_ACTION_CLIENT {
   155  			err = c.App.SendMessageToExtension(w, relayProps["extension_id"], c.Session.Token)
   156  
   157  			if err != nil {
   158  				c.Err = err
   159  				return
   160  			}
   161  		} else {
   162  			http.Redirect(w, r, c.GetSiteURLHeader(), http.StatusFound)
   163  		}
   164  	}
   165  }