test "trying to use expired token redirects to login page" do
visit page_with_token('expired_trustedclient')
- buttons = all("a.btn", text: /Log in/)
+ buttons = all("button.btn", text: /Log in/)
assert_equal(1, buttons.size, "Failed to find one login button")
- login_link = buttons.first[:href]
- assert_match(%r{//[^/]+/login}, login_link)
- assert_no_match(/\bapi_token=/, login_link)
end
end
- api/requests.html.textile.liquid
- api/methods.html.textile.liquid
- api/resources.html.textile.liquid
- - api/tokens_sso.html.textile.liquid
- Permission and authentication:
- api/methods/api_client_authorizations.html.textile.liquid
- api/methods/api_clients.html.textile.liquid
+++ /dev/null
----
-layout: default
-navsection: api
-title: API Authorization with SSO (deprecated)
-...
-{% comment %}
-Copyright (C) The Arvados Authors. All rights reserved.
-
-SPDX-License-Identifier: CC-BY-SA-3.0
-{% endcomment %}
-
-{% include 'notebox_begin_warning' %}
-This page describes the deprecated login flow via the SSO server. SSO server authentication will be removed in a future Arvados release and should not be used for new installations. See "Set up web based login":{{site.baseurl}}/install/setup-login.html for more information.
-{% include 'notebox_end' %}
-
-All requests to the API server must have an API token. API tokens can be issued by going though the login flow, or created via the API. At this time, only browser based applications can perform login from email/password. Command line applications and services must use an API token provided via the @ARVADOS_API_TOKEN@ environment variable or configuration file.
-
-h2. Browser login
-
-Browser based applications can perform log in via the following highlevel flow:
-
-# The web application presents a "login" link to @/login@ on the API server with a @return_to@ parameter provided in the query portion of the URL. For example @https://{{ site.arvados_api_host }}/login?return_to=XXX@ , where @return_to=XXX@ is the URL of the login page for the web application.
-# The "login" link takes the browser to the login page (this may involve several redirects)
-# The user logs in. API server authenticates the user and issues a new API token.
-# The browser is redirected to the login page URL provided in @return_to=XXX@ with the addition of @?api_token=xxxxapitokenxxxx@.
-# The web application gets the login request with the included authorization token.
-
-!{{site.baseurl}}/images/Session_Establishment_with_SSO.svg!
-
-The "browser authentication process is documented in detail on the Arvados wiki.":https://dev.arvados.org/projects/arvados/wiki/Workbench_authentication_process
-
-h2. User activation
-
-"Creation and activation of new users is described here.":{{site.baseurl}}/admin/user-management.html
-
-h2. Creating tokens via the API
-
-The browser login method above issues a new token. Using that token, it is possible to make API calls to create additional tokens. To do so, use the @create@ method of the "API client authorizations":{{site.baseurl}}/api/methods/api_client_authorizations.html resource.
-
-h2. Trusted API clients
-
-The "api_clients":{{site.baseurl}}/api/methods/api_clients.html resource determines if web applications that have gone through the browser login flow may create or list API tokens.
-
-After the user has authenticated, but before an authorization token is issued and browser redirect sent (sending the browser back to the @return_to@ login page bearing @api_token@), the server strips the path and query portion from @return_to@ to get @url_prefix@. The @url_prefix@ is used to find or create an ApiClient object. The newly issued API client authorization (API token) is associated with this ApiClient object.
-
-API clients may be marked as "trusted" by making an API call to create or update an "api_clients":{{site.baseurl}}/api/methods/api_clients.html resource and set the @is_trusted@ flag to @true@. An authorization token associated with a "trusted" client is permitted to list authorization tokens on "API client authorizations":{{site.baseurl}}/api/methods/api_client_authorizations.html .
-
-A authorization token which is not associated with a trusted client may only use the @current@ method to query its own api_client_authorization object. The "untrusted" token is forbidden performing any other operations on API client authorizations, such as listing other authorizations or creating new authorizations.
-
-Authorization tokens which are not issued via the browser login flow (created directly via the API) inherit the api client of the token used to create them. They will always be "trusted" because untrusted API clients cannot create tokens.
-
-h2(#scopes). Scopes
-
-Scopes can restrict a token so it may only access certain resources. This is in addition to normal permission checks for the user associated with the token.
-
-Each entry in scopes consists of a @request_method@ and @request_path@. The @request_method@ is a HTTP method (one of @GET@, @POST@, @PATCH@ or @DELETE@) and @request_path@ is the request URI. A given request is permitted if it matches a scopes exactly, or the scope ends with @/@ and the request string is a prefix of the scope.
-
-As a special case, a scope of @["all"]@ allows all resources. This is the default if no scope is given.
-
-Using scopes is also described on the "Securing API access with scoped tokens":{{site.baseurl}}/admin/scoped-tokens.html page of the admin documentation.
-
-h3. Scope examples
-
-A scope of @GET /arvados/v1/collections@ permits listing collections.
-
-* Requests with different methods, such as creating a new collection using @POST /arvados/v1/collections@, will be rejected.
-* Requests to access other resources, such as @GET /arvados/v1/groups@, will be rejected.
-* Be aware that requests for specific records, such as @GET /arvados/v1/collections/962eh-4zz18-xi32mpz2621o8km@ will also be rejected. This is because the scope @GET /arvados/v1/collections@ does not end in @/@
-
-A scope of @GET /arvados/v1/collections/@ (with @/@ suffix) will permit access to individual collections.
-
-* The request @GET /arvados/v1/collections/962eh-4zz18-xi32mpz2621o8km@ will succeed
-* Be aware that requests for listing @GET /arvados/v1/collections@ (no @/@ suffix) will be rejected, because it is not a match with the rule @GET /arvados/v1/collections/@
-* A listing request @GET /arvados/v1/collections/@ will have the trailing @/@ suffix trimmed before the scope check, as a result it will not match the rule @GET /arvados/v1/collections/@.
-
-To allow both listing objects and requesting individual objects, include both in the scope: @["GET /arvados/v1/collections", "GET /arvados/v1/collections/"]@
-
-A narrow scope such as @GET /arvados/v1/collections/962eh-4zz18-xi32mpz2621o8km@ will disallow listing objects as well as disallow requesting any object other than those listed in the scope.
DispatchCloud:
InternalURLs: {SAMPLE: {}}
ExternalURL: "-"
- SSO:
- InternalURLs: {SAMPLE: {}}
- ExternalURL: ""
Keepproxy:
InternalURLs: {SAMPLE: {}}
ExternalURL: ""
MaxSessions: 100
Login:
- # One of the following mechanisms (SSO, Google, PAM, LDAP, or
+ # One of the following mechanisms (Google, PAM, LDAP, or
# LoginCluster) should be enabled; see
# https://doc.arvados.org/install/setup-login.html
# originally supplied by the user will be used.
UsernameAttribute: uid
- SSO:
- # Authenticate with a separate SSO server. (Deprecated)
- Enable: false
-
- # ProviderAppID and ProviderAppSecret are generated during SSO
- # setup; see
- # https://doc.arvados.org/v2.0/install/install-sso.html#update-config
- ProviderAppID: ""
- ProviderAppSecret: ""
-
Test:
# Authenticate users listed here in the config file. This
# feature is intended to be used in test environments, and
*dst = *n
}
- // Provider* moved to SSO.Provider*
- if dst, n := &cluster.Login.SSO.ProviderAppID, dcluster.Login.ProviderAppID; n != nil && *n != *dst {
- *dst = *n
- if *n != "" {
- // In old config, non-empty ID meant enable
- cluster.Login.SSO.Enable = true
- }
- }
- if dst, n := &cluster.Login.SSO.ProviderAppSecret, dcluster.Login.ProviderAppSecret; n != nil && *n != *dst {
- *dst = *n
- }
-
cfg.Clusters[id] = cluster
}
return nil
"Login.PAM.Enable": true,
"Login.PAM.Service": false,
"Login.RemoteTokenRefresh": true,
- "Login.SSO": true,
- "Login.SSO.Enable": true,
- "Login.SSO.ProviderAppID": false,
- "Login.SSO.ProviderAppSecret": false,
"Login.Test": true,
"Login.Test.Enable": true,
"Login.Test.Users": false,
DispatchCloud:
InternalURLs: {SAMPLE: {}}
ExternalURL: "-"
- SSO:
- InternalURLs: {SAMPLE: {}}
- ExternalURL: ""
Keepproxy:
InternalURLs: {SAMPLE: {}}
ExternalURL: ""
MaxSessions: 100
Login:
- # One of the following mechanisms (SSO, Google, PAM, LDAP, or
+ # One of the following mechanisms (Google, PAM, LDAP, or
# LoginCluster) should be enabled; see
# https://doc.arvados.org/install/setup-login.html
# originally supplied by the user will be used.
UsernameAttribute: uid
- SSO:
- # Authenticate with a separate SSO server. (Deprecated)
- Enable: false
-
- # ProviderAppID and ProviderAppSecret are generated during SSO
- # setup; see
- # https://doc.arvados.org/v2.0/install/install-sso.html#update-config
- ProviderAppID: ""
- ProviderAppSecret: ""
-
Test:
# Authenticate users listed here in the config file. This
# feature is intended to be used in test environments, and
c.Check(jresp["errors"], check.FitsTypeOf, []interface{}{})
}
-func (s *HandlerSuite) TestProxyRedirect(c *check.C) {
- s.cluster.Login.SSO.Enable = true
- s.cluster.Login.SSO.ProviderAppID = "test"
- s.cluster.Login.SSO.ProviderAppSecret = "test"
- req := httptest.NewRequest("GET", "https://0.0.0.0:1/login?return_to=foo", nil)
- resp := httptest.NewRecorder()
- s.handler.ServeHTTP(resp, req)
- if !c.Check(resp.Code, check.Equals, http.StatusFound) {
- c.Log(resp.Body.String())
- }
- // Old "proxy entire request" code path returns an absolute
- // URL. New lib/controller/federation code path returns a
- // relative URL.
- c.Check(resp.Header().Get("Location"), check.Matches, `(https://0.0.0.0:1)?/auth/joshid\?return_to=%2Cfoo&?`)
-}
-
-func (s *HandlerSuite) TestLogoutSSO(c *check.C) {
- s.cluster.Login.SSO.Enable = true
- s.cluster.Login.SSO.ProviderAppID = "test"
- req := httptest.NewRequest("GET", "https://0.0.0.0:1/logout?return_to=https://example.com/foo", nil)
- resp := httptest.NewRecorder()
- s.handler.ServeHTTP(resp, req)
- if !c.Check(resp.Code, check.Equals, http.StatusFound) {
- c.Log(resp.Body.String())
- }
- c.Check(resp.Header().Get("Location"), check.Equals, "http://localhost:3002/users/sign_out?"+url.Values{"redirect_uri": {"https://example.com/foo"}}.Encode())
-}
-
func (s *HandlerSuite) TestLogoutGoogle(c *check.C) {
s.cluster.Login.Google.Enable = true
s.cluster.Login.Google.ClientID = "test"
func chooseLoginController(cluster *arvados.Cluster, parent *Conn) loginController {
wantGoogle := cluster.Login.Google.Enable
wantOpenIDConnect := cluster.Login.OpenIDConnect.Enable
- wantSSO := cluster.Login.SSO.Enable
wantPAM := cluster.Login.PAM.Enable
wantLDAP := cluster.Login.LDAP.Enable
wantTest := cluster.Login.Test.Enable
wantLoginCluster := cluster.Login.LoginCluster != "" && cluster.Login.LoginCluster != cluster.ClusterID
switch {
- case 1 != countTrue(wantGoogle, wantOpenIDConnect, wantSSO, wantPAM, wantLDAP, wantTest, wantLoginCluster):
+ case 1 != countTrue(wantGoogle, wantOpenIDConnect, wantPAM, wantLDAP, wantTest, wantLoginCluster):
return errorLoginController{
- error: errors.New("configuration problem: exactly one of Login.Google, Login.OpenIDConnect, Login.SSO, Login.PAM, Login.LDAP, Login.Test, or Login.LoginCluster must be set"),
+ error: errors.New("configuration problem: exactly one of Login.Google, Login.OpenIDConnect, Login.PAM, Login.LDAP, Login.Test, or Login.LoginCluster must be set"),
}
case wantGoogle:
return &oidcLoginController{
AcceptAccessToken: cluster.Login.OpenIDConnect.AcceptAccessToken,
AcceptAccessTokenScope: cluster.Login.OpenIDConnect.AcceptAccessTokenScope,
}
- case wantSSO:
- return &ssoLoginController{Parent: parent}
case wantPAM:
return &pamLoginController{Cluster: cluster, Parent: parent}
case wantLDAP:
return n
}
-// Login and Logout are passed through to the parent's railsProxy;
-// UserAuthenticate is rejected.
-type ssoLoginController struct{ Parent *Conn }
-
-func (ctrl *ssoLoginController) Login(ctx context.Context, opts arvados.LoginOptions) (arvados.LoginResponse, error) {
- return ctrl.Parent.railsProxy.Login(ctx, opts)
-}
-func (ctrl *ssoLoginController) Logout(ctx context.Context, opts arvados.LogoutOptions) (arvados.LogoutResponse, error) {
- return ctrl.Parent.railsProxy.Logout(ctx, opts)
-}
-func (ctrl *ssoLoginController) UserAuthenticate(ctx context.Context, opts arvados.UserAuthenticateOptions) (arvados.APIClientAuthorization, error) {
- return arvados.APIClientAuthorization{}, httpserver.ErrorWithStatus(errors.New("username/password authentication is not available"), http.StatusBadRequest)
-}
-
type errorLoginController struct{ error }
func (ctrl errorLoginController) Login(context.Context, arvados.LoginOptions) (arvados.LoginResponse, error) {
c.Assert(err, check.IsNil)
s.cluster, err = cfg.GetCluster("")
c.Assert(err, check.IsNil)
- s.cluster.Login.SSO.Enable = false
+ s.cluster.Login.Test.Enable = false
s.cluster.Login.Google.Enable = true
s.cluster.Login.Google.ClientID = "test%client$id"
s.cluster.Login.Google.ClientSecret = "test#client/secret"
opts := arvados.LoginOptions{
ReturnTo: "https://foo.example.com/bar",
}
- resp, err := s.conn.Login(s.ctx, opts)
- c.Check(err, check.IsNil)
- c.Check(resp.RedirectLocation, check.Equals, "/auth/joshid?return_to="+url.QueryEscape(","+opts.ReturnTo))
+ _, err := s.conn.Login(s.ctx, opts)
+ c.Check(err.(*arvados.TransactionError).StatusCode, check.Equals, 404)
}
func (s *RPCSuite) TestLogout(c *check.C) {
}
resp, err := s.conn.Logout(s.ctx, opts)
c.Check(err, check.IsNil)
- c.Check(resp.RedirectLocation, check.Equals, "http://localhost:3002/users/sign_out?redirect_uri="+url.QueryEscape(opts.ReturnTo))
+ c.Check(resp.RedirectLocation, check.Equals, opts.ReturnTo)
}
func (s *RPCSuite) TestCollectionCreate(c *check.C) {
Service string
DefaultEmailDomain string
}
- SSO struct {
- Enable bool
- ProviderAppID string
- ProviderAppSecret string
- }
Test struct {
Enable bool
Users map[string]TestUser
Keepproxy Service
Keepstore Service
RailsAPI Service
- SSO Service
WebDAVDownload Service
WebDAV Service
WebShell Service
"http://%s:%s"%(localhost, keep_web_dl_port): {},
},
},
- "SSO": {
- "ExternalURL": "http://localhost:3002",
- },
}
config = {
"RequestTimeout": "30s",
},
"Login": {
- "SSO": {
+ "Test": {
"Enable": True,
- "ProviderAppID": "arvados-server",
- "ProviderAppSecret": "608dbf356a327e2d0d4932b60161e212c2d8d8f5e25690d7b622f850a990cd33",
+ "Users": {
+ "alice": {
+ "Email": "alice@example.com",
+ "Password": "xyzzy"
+ }
+ }
},
},
"SystemLogs": {
# Locking to 5.10.3 to workaround issue in 5.11.1 (https://github.com/seattlerb/minitest/issues/730)
gem 'minitest', '5.10.3'
-# Restricted because omniauth >= 1.5.0 requires Ruby >= 2.1.9:
-gem 'omniauth', '~> 1.4.0'
-gem 'omniauth-oauth2', '~> 1.1'
-
gem 'andand'
gem 'optimist'
multi_json (~> 1.11)
os (>= 0.9, < 2.0)
signet (~> 0.7)
- hashie (3.6.0)
highline (2.0.1)
httpclient (2.8.3)
i18n (0.9.5)
mocha (1.8.0)
metaclass (~> 0.0.1)
multi_json (1.15.0)
- multi_xml (0.6.0)
multipart-post (2.1.1)
net-scp (2.0.0)
net-ssh (>= 2.6.5, < 6.0.0)
nokogiri (1.11.7)
mini_portile2 (~> 2.5.0)
racc (~> 1.4)
- oauth2 (1.4.1)
- faraday (>= 0.8, < 0.16.0)
- jwt (>= 1.0, < 3.0)
- multi_json (~> 1.3)
- multi_xml (~> 0.5)
- rack (>= 1.2, < 3)
oj (3.9.2)
- omniauth (1.4.3)
- hashie (>= 1.2, < 4)
- rack (>= 1.6.2, < 3)
- omniauth-oauth2 (1.5.0)
- oauth2 (~> 1.1)
- omniauth (~> 1.2)
optimist (3.0.0)
os (1.1.1)
passenger (6.0.2)
mocha
multi_json
oj
- omniauth (~> 1.4.0)
- omniauth-oauth2 (~> 1.1)
optimist
passenger
pg (~> 1.0)
border-bottom: 1px solid #fff;
font-size: 0.8em;
}
-img.curoverse-logo {
+img.arvados-logo {
height: 66px;
}
#intropage {
if not current_user
respond_to do |format|
format.json { send_error("Not logged in", status: 401) }
- format.html { redirect_to '/auth/joshid' }
+ format.html { redirect_to '/login' }
end
false
end
respond_to :html
- # omniauth callback method
+ # create a new session
def create
if !Rails.configuration.Login.LoginCluster.empty? and Rails.configuration.Login.LoginCluster != Rails.configuration.ClusterID
raise "Local login disabled when LoginCluster is set"
authinfo = SafeJSON.load(params[:auth_info])
max_expires_at = authinfo["expires_at"]
else
- # omniauth middleware verified the user and is passing auth_info
- # in request.env.
- authinfo = request.env['omniauth.auth']['info'].with_indifferent_access
+ return send_error "Legacy code path no longer supported", status: 404
end
if !authinfo['user_uuid'].blank?
flash[:notice] = params[:message]
end
- # logout - Clear our rack session BUT essentially redirect to the provider
- # to clean up the Devise session from there too !
+ # logout - this gets intercepted by controller, so this is probably
+ # mostly dead code at this point.
def logout
session[:user_id] = nil
flash[:notice] = 'You have logged off'
return_to = params[:return_to] || root_url
- redirect_to "#{Rails.configuration.Services.SSO.ExternalURL}users/sign_out?redirect_uri=#{CGI.escape return_to}"
+ redirect_to return_to
end
- # login - Just bounce to /auth/joshid. The only purpose of this function is
- # to save the return_to parameter (if it exists; see the application
- # controller). /auth/joshid bypasses the application controller.
+ # login. Redirect to LoginCluster.
def login
if params[:remote] !~ /^[0-9a-z]{5}$/ && !params[:remote].nil?
return send_error 'Invalid remote cluster id', status: 400
p << "return_to=#{CGI.escape(params[:return_to])}" if params[:return_to]
redirect_to "#{login_cluster}/login?#{p.join('&')}"
else
- if params[:return_to]
- # Encode remote param inside callback's return_to, so that we'll get it on
- # create() after login.
- remote_param = params[:remote].nil? ? '' : params[:remote]
- p << "return_to=#{CGI.escape(remote_param + ',' + params[:return_to])}"
- end
- redirect_to "/auth/joshid?#{p.join('&')}"
+ return send_error "Legacy code path no longer supported", status: 404
end
end
<% end %>
•
<a class="logout" href="/logout">Log out</a>
- <% else %>
- <!--<a class="logout" href="/auth/joshid">Log in</a>-->
<% end %>
<% if current_user and session[:real_uid] and session[:switch_back_to] and User.find(session[:real_uid].to_i).verify_userswitch_cookie(session[:switch_back_to]) %>
<% if current_user or session['invite_code'] %>
<div id="footer">
- <div style="float:right">Questions → <a href="mailto:arvados@curoverse.com">arvados@curoverse.com</a></div>
<div style="clear:both"></div>
</div>
<% end %>
});
<% end %>
<div id="intropage">
- <img class="curoverse-logo" src="<%= asset_path('logo.png') %>" style="display:block; margin:2em auto"/>
+ <img class="arvados-logo" src="<%= asset_path('logo.png') %>" style="display:block; margin:2em auto"/>
<div style="width:30em; margin:2em auto 0 auto">
<h1>Welcome</h1>
- <h4>Curoverse ARVADOS</h4>
+ <h4>ARVADOS</h4>
<% if !current_user and session['invite_code'] %>
- <p>Curoverse Arvados lets you manage and process human genomes and exomes. You can start using the private beta
- now with your Google account.</p>
+ <p>Arvados lets you manage and process biomedical data.</p>
<p style="float:right;margin-top:1em">
- <button class="login" href="/auth/joshid">Log in and get started</button>
+ <button class="login" href="/login">Log in and get started</button>
</p>
<% else %>
- <p>Curoverse ARVADOS is transforming how researchers and
- clinical geneticists use whole genome sequences. </p>
- <p>If you’re interested in learning more, we’d love to hear
- from you —
- contact <a href="mailto:arvados@curoverse.com">arvados@curoverse.com</a>.</p>
-
<% if !current_user %>
<p style="float:right;margin-top:1em">
- <a href="/auth/joshid">Log in here.</a>
+ <a href="/login">Log in here.</a>
</p>
<% end %>
<div id="intropage">
- <img class="curoverse-logo" src="<%= asset_path('logo.png') rescue '/logo.png' %>" style="display:block; margin:2em auto"/>
+ <img class="arvados-logo" src="<%= asset_path('logo.png') rescue '/logo.png' %>" style="display:block; margin:2em auto"/>
<div style="width:30em; margin:2em auto 0 auto">
<h1>Error</h1>
<%= notice %>
<br/>
-<a href="/auth/joshid">Retry Login</a>
+<a href="/login">Retry Login</a>
# configured by application.yml (i.e., here!) instead.
end
-if (File.exist?(File.expand_path '../omniauth.rb', __FILE__) and
- not defined? WARNED_OMNIAUTH_CONFIG)
- Rails.logger.warn <<-EOS
-DEPRECATED CONFIGURATION:
- Please move your SSO provider config into config/application.yml
- and delete config/initializers/omniauth.rb.
-EOS
- # Real values will be copied from globals by omniauth_init.rb. For
- # now, assign some strings so the generic *.yml config loader
- # doesn't overwrite them or complain that they're missing.
- Rails.configuration.Login["SSO"]["ProviderAppID"] = 'xxx'
- Rails.configuration.Login["SSO"]["ProviderAppSecret"] = 'xxx'
- Rails.configuration.Services["SSO"]["ExternalURL"] = '//xxx'
- WARNED_OMNIAUTH_CONFIG = true
-end
-
# Load the defaults, used by config:migrate and fallback loading
# legacy application.yml
defaultYAML, stderr, status = Open3.capture3("arvados-server", "config-dump", "-config=-", "-skip-legacy", stdin_data: "Clusters: {xxxxx: {}}")
arvcfg.declare_config "Users.UserNotifierEmailFrom", String, :user_notifier_email_from
arvcfg.declare_config "Users.NewUserNotificationRecipients", Hash, :new_user_notification_recipients, ->(cfg, k, v) { arrayToHash cfg, "Users.NewUserNotificationRecipients", v }
arvcfg.declare_config "Users.NewInactiveUserNotificationRecipients", Hash, :new_inactive_user_notification_recipients, method(:arrayToHash)
-arvcfg.declare_config "Login.SSO.ProviderAppSecret", String, :sso_app_secret
-arvcfg.declare_config "Login.SSO.ProviderAppID", String, :sso_app_id
arvcfg.declare_config "Login.LoginCluster", String
arvcfg.declare_config "Login.TrustedClients", Hash
arvcfg.declare_config "Login.RemoteTokenRefresh", ActiveSupport::Duration
arvcfg.declare_config "Login.TokenLifetime", ActiveSupport::Duration
arvcfg.declare_config "TLS.Insecure", Boolean, :sso_insecure
-arvcfg.declare_config "Services.SSO.ExternalURL", String, :sso_provider_url
arvcfg.declare_config "AuditLogs.MaxAge", ActiveSupport::Duration, :max_audit_log_age
arvcfg.declare_config "AuditLogs.MaxDeleteBatch", Integer, :max_audit_log_delete_batch
arvcfg.declare_config "AuditLogs.UnloggedAttributes", Hash, :unlogged_attributes, ->(cfg, k, v) { arrayToHash cfg, "AuditLogs.UnloggedAttributes", v }
# Load the rails application
require_relative 'application'
-require 'josh_id'
# Initialize the rails application
Rails.application.initialize!
+++ /dev/null
-# Copyright (C) The Arvados Authors. All rights reserved.
-#
-# SPDX-License-Identifier: AGPL-3.0
-
-# This file is called omniauth_init.rb instead of omniauth.rb because
-# older versions had site configuration in omniauth.rb.
-#
-# It must come after omniauth.rb in (lexical) load order.
-
-if defined? CUSTOM_PROVIDER_URL
- Rails.logger.warn "Copying omniauth from globals in legacy config file."
- Rails.configuration.Login["SSO"]["ProviderAppID"] = APP_ID
- Rails.configuration.Login["SSO"]["ProviderAppSecret"] = APP_SECRET
- Rails.configuration.Services["SSO"]["ExternalURL"] = CUSTOM_PROVIDER_URL.sub(/\/$/, "") + "/"
-else
- Rails.application.config.middleware.use OmniAuth::Builder do
- provider(:josh_id,
- Rails.configuration.Login["SSO"]["ProviderAppID"],
- Rails.configuration.Login["SSO"]["ProviderAppSecret"],
- Rails.configuration.Services["SSO"]["ExternalURL"])
- end
- OmniAuth.config.on_failure = StaticController.action(:login_failure)
-end
+++ /dev/null
-# Copyright (C) The Arvados Authors. All rights reserved.
-#
-# SPDX-License-Identifier: AGPL-3.0
-
-require 'omniauth-oauth2'
-module OmniAuth
- module Strategies
- class JoshId < OmniAuth::Strategies::OAuth2
-
- args [:client_id, :client_secret, :custom_provider_url]
-
- option :custom_provider_url, ''
-
- uid { raw_info['id'] }
-
- option :client_options, {}
-
- info do
- {
- :first_name => raw_info['info']['first_name'],
- :last_name => raw_info['info']['last_name'],
- :email => raw_info['info']['email'],
- :identity_url => raw_info['info']['identity_url'],
- :username => raw_info['info']['username'],
- }
- end
-
- extra do
- {
- 'raw_info' => raw_info
- }
- end
-
- def authorize_params
- options.authorize_params[:auth_provider] = request.params['auth_provider']
- super
- end
-
- def client
- options.client_options[:site] = options[:custom_provider_url]
- options.client_options[:authorize_url] = "#{options[:custom_provider_url]}/auth/josh_id/authorize"
- options.client_options[:access_token_url] = "#{options[:custom_provider_url]}/auth/josh_id/access_token"
- if Rails.configuration.TLS.Insecure
- options.client_options[:ssl] = {verify_mode: OpenSSL::SSL::VERIFY_NONE}
- end
- ::OAuth2::Client.new(options.client_id, options.client_secret, deep_symbolize(options.client_options))
- end
-
- def callback_url
- full_host + script_name + callback_path + "?return_to=" + CGI.escape(request.params['return_to'] || '')
- end
-
- def raw_info
- @raw_info ||= access_token.get("/auth/josh_id/user.json?oauth_token=#{access_token.token}").parsed
- end
- end
- end
-end
test "redirect to joshid" do
api_client_page = 'http://client.example.com/home'
get :login, params: {return_to: api_client_page}
- assert_response :redirect
- assert_equal("http://test.host/auth/joshid?return_to=%2Chttp%3A%2F%2Fclient.example.com%2Fhome", @response.redirect_url)
- assert_nil assigns(:api_client)
+ # Not supported any more
+ assert_response 404
end
test "send token when user is already logged in" do
Rails.configuration.Login.LoginCluster = 'zzzzz'
api_client_page = 'http://client.example.com/home'
get :login, params: {return_to: api_client_page}
- assert_response :redirect
- assert_equal("http://test.host/auth/joshid?return_to=%2Chttp%3A%2F%2Fclient.example.com%2Fhome", @response.redirect_url)
- assert_nil assigns(:api_client)
+ # Doesn't redirect, just fail.
+ assert_response 404
end
test "controller cannot create session without SystemRootToken" do
params: {specimen: {}},
headers: {'HTTP_ACCEPT' => 'text/html'})
assert_response 302
- assert_match(%r{/auth/joshid$}, @response.headers['Location'],
+ assert_match(%r{http://www.example.com/login$}, @response.headers['Location'],
"HTML login prompt did not include expected redirect")
end
end
def mock_auth_with(email: nil, username: nil, identity_url: nil, remote: nil, expected_response: :redirect)
mock = {
- 'provider' => 'josh_id',
- 'uid' => 'https://edward.example.com',
- 'info' => {
'identity_url' => 'https://edward.example.com',
'name' => 'Edward Example',
'first_name' => 'Edward',
'last_name' => 'Example',
- },
}
- mock['info']['email'] = email unless email.nil?
- mock['info']['username'] = username unless username.nil?
- mock['info']['identity_url'] = identity_url unless identity_url.nil?
- post('/auth/josh_id/callback',
- params: {return_to: client_url(remote: remote)},
- headers: {'omniauth.auth' => mock})
+ mock['email'] = email unless email.nil?
+ mock['username'] = username unless username.nil?
+ mock['identity_url'] = identity_url unless identity_url.nil?
+ post('/auth/controller/callback',
+ params: {return_to: client_url(remote: remote), :auth_info => SafeJSON.dump(mock)},
+ headers: {'Authorization' => 'Bearer ' + Rails.configuration.SystemRootToken})
errors = {
:redirect => 'Did not redirect to client with token',
SimpleCov.start do
add_filter '/test/'
add_filter 'initializers/secret_token'
- add_filter 'initializers/omniauth'
end
rescue Exception => e
$stderr.puts "SimpleCov unavailable (#{e}). Proceeding without."