Skip to content

Commit 049a559

Browse files
authored
Merge branch 'master' into remove_mistral
2 parents a88e797 + af9c6d6 commit 049a559

File tree

19 files changed

+612
-8
lines changed

19 files changed

+612
-8
lines changed

Makefile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,12 @@ requirements: virtualenv .requirements .sdist-requirements install-runners insta
564564
# make targets. This speeds up the build
565565
(cd ${ROOT_DIR}/st2common; ${ROOT_DIR}/$(VIRTUALENV_DIR)/bin/python setup.py develop --no-deps)
566566

567+
# Install st2auth to register SSO drivers
568+
# NOTE: We pass --no-deps to the script so we don't install all the
569+
# package dependencies which are already installed as part of "requirements"
570+
# make targets. This speeds up the build
571+
(cd ${ROOT_DIR}/st2auth; ${ROOT_DIR}/$(VIRTUALENV_DIR)/bin/python setup.py develop --no-deps)
572+
567573
# Some of the tests rely on submodule so we need to make sure submodules are check out
568574
git submodule update --recursive --remote
569575

OWNERS.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ This page lists active project maintainers and their areas of expertise. This ca
1212
Responsible for Project Strategy, External Relations, Organizational aspects, Partnerships and Future.
1313
* Dmitri Zimine ([@dzimine](https://github.com/dzimine/)) <<dzimine@stackstorm.com>>
1414
- StackStorm co-founder. External Relations, Leadership.
15-
* Lindsay Hill ([@LindsayHill](https://github.com/LindsayHill)) <<lindsay@stackstorm.com>>
16-
- External Relations, Plans, Documentation, Community.
1715

1816
# Senior Maintainers **
1917
###### 2 vote points
@@ -48,11 +46,13 @@ Being part of Technical Steering Committee (TSC) [@StackStorm/maintainers](https
4846
Contributors are using and occasionally contributing back to the project, might be active in conversations or express their opinion on the project’s direction.
4947
They're not part of the TSC voting process, but appreciated for their contribution, involvement and may become Maintainers in the future depending on their effort and involvement. See [How to become a Maintainer?](https://github.com/StackStorm/st2/blob/master/GOVERNANCE.md#how-to-become-a-maintainer)
5048
[@StackStorm/contributors](https://github.com/orgs/StackStorm/teams/contributors) are invited to StackStorm Github organization and have permissions to help triage the Issues and review PRs.
49+
* AJ Jonen ([@guzzijones](https://github.com/guzzijones)) - ST2 Web UI, Orquesta, Core.
5150
* Carlos ([@nzlosh](https://github.com/nzlosh)) - Chatops, Errbot, Community, Discussions, StackStorm Exchange.
5251
* Hiroyasu Ohyama ([@userlocalhost](https://github.com/userlocalhost)) - Orquesta, Workflows, st2 Japan Community. [Case Study](https://stackstorm.com/case-study-dmm/).
5352
* Jon Middleton ([@jjm](https://github.com/jjm)) - StackStorm Exchange, Core, Discussions.
54-
* Tristan Struthers ([@trstruth](https://github.com/trstruth)) - Docker, K8s, Orquesta, Community.
5553
* Marcel Weinberg ([@winem](https://github.com/winem)) - Community, Docker, Core.
54+
* Sheshagiri Rao Mallipedhi ([@sheshagiri](https://github.com/sheshagiri)) - Docker, Core, StackStorm Exchange.
55+
* Tristan Struthers ([@trstruth](https://github.com/trstruth)) - Docker, K8s, Orquesta, Community.
5656

5757
# Friends
5858
People that are currently not very active maintainers/contributors but who participated in and formed the project we have today.
@@ -73,6 +73,7 @@ Thank you, Friends!
7373
* Johan Dahlberg ([@johandahlberg](https://github.com/johandahlberg)) - Using st2 for Bioinformatics/Science project, providing feedback & contributions in Ansible, Community, Workflows. [Case Study](https://stackstorm.com/case-study-scilifelab/).
7474
* Johan Hermansson ([@johanherman](https://github.com/johanherman)) - Using st2 for Bioinformatics/Science project, feedback & contributions in Ansible, Community, Workflows. [Case Study](https://stackstorm.com/case-study-scilifelab/).
7575
* Lakshmi Kannan ([@lakshmi-kannan](https://github.com/lakshmi-kannan)) - early Stormer. Initial Core platform architecture, scalability, reliability, Team Leadership during the project hard times.
76+
* Lindsay Hill ([@LindsayHill](https://github.com/LindsayHill)) - ex StackStorm product manager that made a significant impact building an ecosystem we see today.
7677
* Manas Kelshikar ([@manasdk](https://github.com/manasdk)) - ex Stormer. Developed (well) early core platform features.
7778
* Vineesh Jain ([@VineeshJain](https://github.com/VineeshJain)) - ex Stormer. Community, Tests, Core, QA.
7879
* Warren Van Winckel ([@warrenvw](https://github.com/warrenvw)) - ex Stormer. Docker, Kubernetes, Vagrant, Infrastructure.

conf/st2.conf.sample

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ port = 9101
5353
# Common option - options below apply in both scenarios - when auth service is running as a WSGI
5454
# service (e.g. under Apache or Nginx) and when it's running in the standalone mode.
5555

56+
# JSON serialized arguments which are passed to the SSO backend.
57+
sso_backend_kwargs = None
5658
# Enable authentication middleware.
5759
enable = True
5860
# Path to the logging config.
@@ -63,10 +65,14 @@ api_url = None
6365
service_token_ttl = 86400
6466
# Access token ttl in seconds.
6567
token_ttl = 86400
68+
# Enable Single Sign On for GUI if true.
69+
sso = False
6670
# Authentication mode (proxy,standalone)
6771
mode = standalone
6872
# Specify to enable debug mode.
6973
debug = False
74+
# Single Sign On backend to use when SSO is enabled. Available backends: noop, saml2.
75+
sso_backend = noop
7076

7177
# Standalone mode options - options below only apply when auth service is running in the standalone
7278
# mode.

st2auth/setup.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,10 @@
4646
packages=find_packages(exclude=['setuptools', 'tests']),
4747
scripts=[
4848
'bin/st2auth'
49-
]
49+
],
50+
entry_points={
51+
'st2auth.sso.backends': [
52+
'noop = st2auth.sso.noop:NoOpSingleSignOnBackend'
53+
]
54+
}
5055
)

st2auth/st2auth/app.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from st2common.constants.system import VERSION_STRING
2727
from st2common.service_setup import setup as common_setup
2828
from st2common.util import spec_loader
29+
from st2common.util.monkey_patch import use_select_poll_workaround
2930
from st2auth import config as st2auth_config
3031
from st2auth.validation import validate_auth_backend_is_correctly_configured
3132

@@ -61,6 +62,10 @@ def setup_app(config=None):
6162
capabilities=capabilities,
6263
config_args=config.get('config_args', None))
6364

65+
# pysaml2 uses subprocess communicate which calls communicate_with_poll
66+
if cfg.CONF.auth.sso and cfg.CONF.auth.sso_backend == 'saml2':
67+
use_select_poll_workaround(nose_only=False)
68+
6469
# Additional pre-run time checks
6570
validate_auth_backend_is_correctly_configured()
6671

st2auth/st2auth/config.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@
2222
from st2common.constants.system import DEFAULT_CONFIG_FILE_PATH
2323
from st2common.constants.auth import DEFAULT_MODE
2424
from st2common.constants.auth import DEFAULT_BACKEND
25+
from st2common.constants.auth import DEFAULT_SSO_BACKEND
2526
from st2common.constants.auth import VALID_MODES
26-
from st2auth.backends import get_available_backends
27+
from st2auth import backends as auth_backends
2728

2829

2930
def parse_args(args=None):
@@ -45,7 +46,8 @@ def _register_common_opts():
4546

4647

4748
def _register_app_opts():
48-
available_backends = get_available_backends()
49+
available_backends = auth_backends.get_available_backends()
50+
4951
auth_opts = [
5052
cfg.StrOpt(
5153
'host', default='127.0.0.1',
@@ -78,7 +80,17 @@ def _register_app_opts():
7880
cfg.StrOpt(
7981
'backend_kwargs', default=None,
8082
help='JSON serialized arguments which are passed to the authentication '
81-
'backend in a standalone mode.')
83+
'backend in a standalone mode.'),
84+
cfg.BoolOpt(
85+
'sso', default=False,
86+
help='Enable Single Sign On for GUI if true.'),
87+
cfg.StrOpt(
88+
'sso_backend', default=DEFAULT_SSO_BACKEND,
89+
help='Single Sign On backend to use when SSO is enabled. Available '
90+
'backends: noop, saml2.'),
91+
cfg.StrOpt(
92+
'sso_backend_kwargs', default=None,
93+
help='JSON serialized arguments which are passed to the SSO backend.')
8294
]
8395

8496
cfg.CONF.register_cli_opts(auth_opts, group='auth')

st2auth/st2auth/controllers/v1/root.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414
# limitations under the License.
1515

1616
from st2auth.controllers.v1 import auth
17+
from st2auth.controllers.v1 import sso as sso_auth
1718

1819

1920
class RootController(object):
2021
tokens = auth.TokenController()
22+
sso = sso_auth.SingleSignOnController()

st2auth/st2auth/controllers/v1/sso.py

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# Copyright 2019 Extreme Networks, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import datetime
16+
import json
17+
18+
from oslo_config import cfg
19+
from six.moves import http_client
20+
from six.moves import urllib
21+
22+
import st2auth.handlers as handlers
23+
24+
from st2auth import sso as st2auth_sso
25+
from st2common.exceptions import auth as auth_exc
26+
from st2common import log as logging
27+
from st2common import router
28+
29+
30+
LOG = logging.getLogger(__name__)
31+
SSO_BACKEND = st2auth_sso.get_sso_backend()
32+
33+
34+
class IdentityProviderCallbackController(object):
35+
36+
def __init__(self):
37+
self.st2_auth_handler = handlers.ProxyAuthHandler()
38+
39+
def post(self, response, **kwargs):
40+
try:
41+
verified_user = SSO_BACKEND.verify_response(response)
42+
43+
st2_auth_token_create_request = {'user': verified_user['username'], 'ttl': None}
44+
45+
st2_auth_token = self.st2_auth_handler.handle_auth(
46+
request=st2_auth_token_create_request,
47+
remote_addr=verified_user['referer'],
48+
remote_user=verified_user['username'],
49+
headers={}
50+
)
51+
52+
return process_successful_authn_response(verified_user['referer'], st2_auth_token)
53+
except NotImplementedError as e:
54+
return process_failure_response(http_client.INTERNAL_SERVER_ERROR, e)
55+
except auth_exc.SSOVerificationError as e:
56+
return process_failure_response(http_client.UNAUTHORIZED, e)
57+
except Exception as e:
58+
raise e
59+
60+
61+
class SingleSignOnRequestController(object):
62+
63+
def get(self, referer):
64+
try:
65+
response = router.Response(status=http_client.TEMPORARY_REDIRECT)
66+
response.location = SSO_BACKEND.get_request_redirect_url(referer)
67+
return response
68+
except NotImplementedError as e:
69+
return process_failure_response(http_client.INTERNAL_SERVER_ERROR, e)
70+
except Exception as e:
71+
raise e
72+
73+
74+
class SingleSignOnController(object):
75+
request = SingleSignOnRequestController()
76+
callback = IdentityProviderCallbackController()
77+
78+
def _get_sso_enabled_config(self):
79+
return {'enabled': cfg.CONF.auth.sso}
80+
81+
def get(self):
82+
try:
83+
result = self._get_sso_enabled_config()
84+
return process_successful_response(http_client.OK, result)
85+
except Exception:
86+
LOG.exception('Error encountered while getting SSO configuration.')
87+
result = {'enabled': False}
88+
return process_successful_response(http_client.OK, result)
89+
90+
91+
CALLBACK_SUCCESS_RESPONSE_BODY = """
92+
<html>
93+
<script>
94+
function getCookie(name) {
95+
var v = document.cookie.match('(^|;) ?' + name + '=([^;]*)(;|$)');
96+
return v ? v[2] : null;
97+
}
98+
99+
data = JSON.parse(window.localStorage.getItem('st2Session'));
100+
data['token'] = JSON.parse(decodeURIComponent(getCookie('st2-auth-token')));
101+
window.localStorage.setItem('st2Session', JSON.stringify(data));
102+
window.location.replace("%s");
103+
</script>
104+
</html>
105+
"""
106+
107+
108+
def process_successful_authn_response(referer, token):
109+
token_json = {
110+
'id': str(token.id),
111+
'user': token.user,
112+
'token': token.token,
113+
'expiry': str(token.expiry),
114+
'service': False,
115+
'metadata': {}
116+
}
117+
118+
body = CALLBACK_SUCCESS_RESPONSE_BODY % referer
119+
resp = router.Response(body=body)
120+
resp.headers['Content-Type'] = 'text/html'
121+
122+
resp.set_cookie(
123+
'st2-auth-token',
124+
value=urllib.parse.quote(json.dumps(token_json)),
125+
expires=datetime.timedelta(seconds=60),
126+
overwrite=True
127+
)
128+
129+
return resp
130+
131+
132+
def process_successful_response(status_code, json_body):
133+
return router.Response(status_code=status_code, json_body=json_body)
134+
135+
136+
def process_failure_response(status_code, exception):
137+
LOG.error(str(exception))
138+
json_body = {'faultstring': str(exception)}
139+
return router.Response(status_code=status_code, json_body=json_body)
140+
141+
142+
sso_controller = SingleSignOnController()
143+
sso_request_controller = SingleSignOnRequestController()
144+
idp_callback_controller = IdentityProviderCallbackController()

st2auth/st2auth/sso/__init__.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Copyright 2019 Extreme Networks, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from __future__ import absolute_import
16+
17+
import json
18+
import six
19+
import traceback
20+
21+
from oslo_config import cfg
22+
23+
from st2common import log as logging
24+
25+
from st2common.util import driver_loader
26+
27+
28+
__all__ = [
29+
'get_available_backends',
30+
'get_backend_instance',
31+
'get_sso_backend'
32+
]
33+
34+
LOG = logging.getLogger(__name__)
35+
36+
BACKENDS_NAMESPACE = 'st2auth.sso.backends'
37+
38+
39+
def get_available_backends():
40+
return driver_loader.get_available_backends(namespace=BACKENDS_NAMESPACE)
41+
42+
43+
def get_backend_instance(name):
44+
sso_backend_cls = driver_loader.get_backend_driver(namespace=BACKENDS_NAMESPACE, name=name)
45+
46+
kwargs = {}
47+
sso_backend_kwargs = cfg.CONF.auth.sso_backend_kwargs
48+
49+
if sso_backend_kwargs:
50+
try:
51+
kwargs = json.loads(sso_backend_kwargs)
52+
except ValueError as e:
53+
raise ValueError(
54+
'Failed to JSON parse backend settings for backend "%s": %s' %
55+
(name, six.text_type(e))
56+
)
57+
58+
try:
59+
sso_backend = sso_backend_cls(**kwargs)
60+
except Exception as e:
61+
tb_msg = traceback.format_exc()
62+
class_name = sso_backend_cls.__name__
63+
msg = ('Failed to instantiate SSO backend "%s" (class %s) with backend settings '
64+
'"%s": %s' % (name, class_name, str(kwargs), six.text_type(e)))
65+
msg += '\n\n' + tb_msg
66+
exc_cls = type(e)
67+
raise exc_cls(msg)
68+
69+
return sso_backend
70+
71+
72+
def get_sso_backend():
73+
"""
74+
Return SingleSignOnBackend class instance.
75+
"""
76+
return get_backend_instance(cfg.CONF.auth.sso_backend)

0 commit comments

Comments
 (0)