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 }