github.com/cjdelisle/matterfoss@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 }