2019-01-16 15:01:38 +00:00
package auth
import (
"log"
"net/http"
2019-01-18 08:13:33 +00:00
"github.com/asaskevich/govalidator"
2019-01-16 15:01:38 +00:00
httperror "github.com/portainer/libhttp/error"
"github.com/portainer/libhttp/request"
"github.com/portainer/portainer"
)
2019-01-18 08:13:33 +00:00
type oauthPayload struct {
Code string
}
func ( payload * oauthPayload ) Validate ( r * http . Request ) error {
if govalidator . IsNull ( payload . Code ) {
return portainer . Error ( "Invalid OAuth authorization code" )
}
return nil
}
2019-01-18 08:15:02 +00:00
func ( handler * Handler ) validateOAuth ( w http . ResponseWriter , r * http . Request ) * httperror . HandlerError {
2019-01-16 15:01:38 +00:00
var payload oauthPayload
err := request . DecodeAndValidateJSONPayload ( r , & payload )
if err != nil {
return & httperror . HandlerError { http . StatusBadRequest , "Invalid request payload" , err }
}
settings , err := handler . SettingsService . Settings ( )
if err != nil {
return & httperror . HandlerError { http . StatusInternalServerError , "Unable to retrieve settings from the database" , err }
}
if settings . AuthenticationMethod != 3 {
return & httperror . HandlerError { http . StatusForbidden , "OAuth authentication is not being used" , err }
}
token , err := handler . OAuthService . GetAccessToken ( payload . Code , & settings . OAuthSettings )
if err != nil {
log . Printf ( "[DEBUG] - Failed retrieving access token: %v" , err )
return & httperror . HandlerError { http . StatusUnprocessableEntity , "Invalid access token" , portainer . ErrUnauthorized }
}
username , err := handler . OAuthService . GetUsername ( token , & settings . OAuthSettings )
if err != nil {
log . Printf ( "[DEBUG] - Failed acquiring username: %v" , err )
return & httperror . HandlerError { http . StatusForbidden , "Unable to acquire username" , portainer . ErrUnauthorized }
}
2019-01-18 08:56:16 +00:00
user , err := handler . UserService . UserByUsername ( username )
2019-01-16 15:01:38 +00:00
if err != nil && err != portainer . ErrObjectNotFound {
return & httperror . HandlerError { http . StatusInternalServerError , "Unable to retrieve a user with the specified username from the database" , err }
}
2019-01-18 08:56:16 +00:00
if user == nil && ! settings . OAuthSettings . OAuthAutoCreateUsers {
2019-02-14 02:58:45 +00:00
return & httperror . HandlerError { http . StatusForbidden , "Account not created beforehand in Portainer and automatic user provisioning not enabled" , portainer . ErrUnauthorized }
2019-01-16 15:01:38 +00:00
}
2019-01-18 08:56:16 +00:00
if user == nil {
user = & portainer . User {
2019-01-16 15:01:38 +00:00
Username : username ,
Role : portainer . StandardUserRole ,
}
err = handler . UserService . CreateUser ( user )
if err != nil {
return & httperror . HandlerError { http . StatusInternalServerError , "Unable to persist user inside the database" , err }
}
}
2019-01-18 08:56:16 +00:00
return handler . writeToken ( w , user )
2019-01-16 15:01:38 +00:00
}
2019-01-18 08:13:33 +00:00
func ( handler * Handler ) loginOAuth ( w http . ResponseWriter , r * http . Request ) * httperror . HandlerError {
settings , err := handler . SettingsService . Settings ( )
if err != nil {
return & httperror . HandlerError { http . StatusInternalServerError , "Unable to retrieve settings from the database" , err }
}
if settings . AuthenticationMethod != 3 {
return & httperror . HandlerError { http . StatusForbidden , "OAuth authentication is disabled" , err }
}
2019-01-18 08:56:16 +00:00
url := handler . OAuthService . BuildLoginURL ( & settings . OAuthSettings )
2019-01-18 08:13:33 +00:00
http . Redirect ( w , r , url , http . StatusTemporaryRedirect )
return nil
}