github.com/qichengzx/mattermost-server@v4.5.1-0.20180604164826-2c75247c97d0+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/app"
    12  	"github.com/mattermost/mattermost-server/mlog"
    13  	"github.com/mattermost/mattermost-server/model"
    14  )
    15  
    16  func (w *Web) InitSaml() {
    17  	w.MainRouter.Handle("/login/sso/saml", w.NewHandler(loginWithSaml)).Methods("GET")
    18  	w.MainRouter.Handle("/login/sso/saml", w.NewHandler(completeSaml)).Methods("POST")
    19  }
    20  
    21  func loginWithSaml(c *Context, w http.ResponseWriter, r *http.Request) {
    22  	samlInterface := c.App.Saml
    23  
    24  	if samlInterface == nil {
    25  		c.Err = model.NewAppError("loginWithSaml", "api.user.saml.not_available.app_error", nil, "", http.StatusFound)
    26  		return
    27  	}
    28  
    29  	teamId, err := c.App.GetTeamIdFromQuery(r.URL.Query())
    30  	if err != nil {
    31  		c.Err = err
    32  		return
    33  	}
    34  	action := r.URL.Query().Get("action")
    35  	redirectTo := r.URL.Query().Get("redirect_to")
    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(relayProps) > 0 {
    52  		relayState = b64.StdEncoding.EncodeToString([]byte(model.MapToJson(relayProps)))
    53  	}
    54  
    55  	if data, err := samlInterface.BuildRequest(relayState); err != nil {
    56  		c.Err = err
    57  		return
    58  	} else {
    59  		w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
    60  		http.Redirect(w, r, data.URL, http.StatusFound)
    61  	}
    62  }
    63  
    64  func completeSaml(c *Context, w http.ResponseWriter, r *http.Request) {
    65  	samlInterface := c.App.Saml
    66  
    67  	if samlInterface == nil {
    68  		c.Err = model.NewAppError("completeSaml", "api.user.saml.not_available.app_error", nil, "", http.StatusFound)
    69  		return
    70  	}
    71  
    72  	//Validate that the user is with SAML and all that
    73  	encodedXML := r.FormValue("SAMLResponse")
    74  	relayState := r.FormValue("RelayState")
    75  
    76  	relayProps := make(map[string]string)
    77  	if len(relayState) > 0 {
    78  		stateStr := ""
    79  		if b, err := b64.StdEncoding.DecodeString(relayState); err != nil {
    80  			c.Err = model.NewAppError("completeSaml", "api.user.authorize_oauth_user.invalid_state.app_error", nil, err.Error(), http.StatusFound)
    81  			return
    82  		} else {
    83  			stateStr = string(b)
    84  		}
    85  		relayProps = model.MapFromJson(strings.NewReader(stateStr))
    86  	}
    87  
    88  	action := relayProps["action"]
    89  	if user, err := samlInterface.DoLogin(encodedXML, relayProps); err != nil {
    90  		if action == model.OAUTH_ACTION_MOBILE {
    91  			err.Translate(c.T)
    92  			w.Write([]byte(err.ToJson()))
    93  		} else {
    94  			c.Err = err
    95  			c.Err.StatusCode = http.StatusFound
    96  		}
    97  		return
    98  	} else {
    99  		if err := c.App.CheckUserAllAuthenticationCriteria(user, ""); err != nil {
   100  			c.Err = err
   101  			c.Err.StatusCode = http.StatusFound
   102  			return
   103  		}
   104  
   105  		switch action {
   106  		case model.OAUTH_ACTION_SIGNUP:
   107  			teamId := relayProps["team_id"]
   108  			if len(teamId) > 0 {
   109  				c.App.Go(func() {
   110  					if err := c.App.AddUserToTeamByTeamId(teamId, user); err != nil {
   111  						mlog.Error(err.Error())
   112  					} else {
   113  						c.App.AddDirectChannels(teamId, user)
   114  					}
   115  				})
   116  			}
   117  		case model.OAUTH_ACTION_EMAIL_TO_SSO:
   118  			if err := c.App.RevokeAllSessions(user.Id); err != nil {
   119  				c.Err = err
   120  				return
   121  			}
   122  			c.LogAuditWithUserId(user.Id, "Revoked all sessions for user")
   123  			c.App.Go(func() {
   124  				if err := c.App.SendSignInChangeEmail(user.Email, strings.Title(model.USER_AUTH_SERVICE_SAML)+" SSO", user.Locale, c.App.GetSiteURL()); err != nil {
   125  					mlog.Error(err.Error())
   126  				}
   127  			})
   128  		}
   129  
   130  		session, err := c.App.DoLogin(w, r, user, "")
   131  		if err != nil {
   132  			c.Err = err
   133  			return
   134  		}
   135  
   136  		c.Session = *session
   137  
   138  		if val, ok := relayProps["redirect_to"]; ok {
   139  			http.Redirect(w, r, c.GetSiteURLHeader()+val, http.StatusFound)
   140  			return
   141  		}
   142  
   143  		if action == model.OAUTH_ACTION_MOBILE {
   144  			ReturnStatusOK(w)
   145  		} else {
   146  			http.Redirect(w, r, app.GetProtocol(r)+"://"+r.Host, http.StatusFound)
   147  		}
   148  	}
   149  }