github.com/space0122/mattermost-server@v5.11.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  	relayProps := map[string]string{}
    36  	relayState := ""
    37  
    38  	if len(action) != 0 {
    39  		relayProps["team_id"] = teamId
    40  		relayProps["action"] = action
    41  		if action == model.OAUTH_ACTION_EMAIL_TO_SSO {
    42  			relayProps["email"] = r.URL.Query().Get("email")
    43  		}
    44  	}
    45  
    46  	if len(redirectTo) != 0 {
    47  		relayProps["redirect_to"] = redirectTo
    48  	}
    49  
    50  	if len(relayProps) > 0 {
    51  		relayState = b64.StdEncoding.EncodeToString([]byte(model.MapToJson(relayProps)))
    52  	}
    53  
    54  	if data, err := samlInterface.BuildRequest(relayState); err != nil {
    55  		c.Err = err
    56  		return
    57  	} else {
    58  		w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
    59  		http.Redirect(w, r, data.URL, http.StatusFound)
    60  	}
    61  }
    62  
    63  func completeSaml(c *Context, w http.ResponseWriter, r *http.Request) {
    64  	samlInterface := c.App.Saml
    65  
    66  	if samlInterface == nil {
    67  		c.Err = model.NewAppError("completeSaml", "api.user.saml.not_available.app_error", nil, "", http.StatusFound)
    68  		return
    69  	}
    70  
    71  	//Validate that the user is with SAML and all that
    72  	encodedXML := r.FormValue("SAMLResponse")
    73  	relayState := r.FormValue("RelayState")
    74  
    75  	relayProps := make(map[string]string)
    76  	if len(relayState) > 0 {
    77  		stateStr := ""
    78  		if b, err := b64.StdEncoding.DecodeString(relayState); err != nil {
    79  			c.Err = model.NewAppError("completeSaml", "api.user.authorize_oauth_user.invalid_state.app_error", nil, err.Error(), http.StatusFound)
    80  			return
    81  		} else {
    82  			stateStr = string(b)
    83  		}
    84  		relayProps = model.MapFromJson(strings.NewReader(stateStr))
    85  	}
    86  
    87  	action := relayProps["action"]
    88  	if user, err := samlInterface.DoLogin(encodedXML, relayProps); err != nil {
    89  		if action == model.OAUTH_ACTION_MOBILE {
    90  			err.Translate(c.App.T)
    91  			w.Write([]byte(err.ToJson()))
    92  		} else {
    93  			c.Err = err
    94  			c.Err.StatusCode = http.StatusFound
    95  		}
    96  		return
    97  	} else {
    98  		if err := c.App.CheckUserAllAuthenticationCriteria(user, ""); err != nil {
    99  			c.Err = err
   100  			c.Err.StatusCode = http.StatusFound
   101  			return
   102  		}
   103  
   104  		switch action {
   105  		case model.OAUTH_ACTION_SIGNUP:
   106  			teamId := relayProps["team_id"]
   107  			if len(teamId) > 0 {
   108  				c.App.Srv.Go(func() {
   109  					if err := c.App.AddUserToTeamByTeamId(teamId, user); err != nil {
   110  						mlog.Error(err.Error())
   111  					} else {
   112  						c.App.AddDirectChannels(teamId, user)
   113  					}
   114  				})
   115  			}
   116  		case model.OAUTH_ACTION_EMAIL_TO_SSO:
   117  			if err := c.App.RevokeAllSessions(user.Id); err != nil {
   118  				c.Err = err
   119  				return
   120  			}
   121  			c.LogAuditWithUserId(user.Id, "Revoked all sessions for user")
   122  			c.App.Srv.Go(func() {
   123  				if err := c.App.SendSignInChangeEmail(user.Email, strings.Title(model.USER_AUTH_SERVICE_SAML)+" SSO", user.Locale, c.App.GetSiteURL()); err != nil {
   124  					mlog.Error(err.Error())
   125  				}
   126  			})
   127  		}
   128  
   129  		session, err := c.App.DoLogin(w, r, user, "")
   130  		if err != nil {
   131  			c.Err = err
   132  			return
   133  		}
   134  
   135  		c.App.AttachSessionCookies(w, r, session)
   136  
   137  		c.App.Session = *session
   138  
   139  		if val, ok := relayProps["redirect_to"]; ok {
   140  			http.Redirect(w, r, c.GetSiteURLHeader()+val, http.StatusFound)
   141  			return
   142  		}
   143  
   144  		switch action {
   145  		case model.OAUTH_ACTION_MOBILE:
   146  			ReturnStatusOK(w)
   147  		case model.OAUTH_ACTION_EMAIL_TO_SSO:
   148  			http.Redirect(w, r, c.GetSiteURLHeader()+"/login?extra=signin_change", http.StatusFound)
   149  		default:
   150  			http.Redirect(w, r, c.GetSiteURLHeader(), http.StatusFound)
   151  		}
   152  	}
   153  }