Jenkins RoleBasedAuthorizationStrategy with OIDC and externally managed role assignments - jenkins

I am trying to find a way to use the roles I manage in Okta to work with Jenkins. I have been trying to get role-strategy plugin to work, but when I log in, I get <user> is missing the Overall/Read permission.
My configuration includes OIDC for Okta, using oic-auth plugin, and I am specifying the authorizationStrategy config via JCasC. For example I have this on my JCasC okta.yaml:
authorizationStrategy:
roleBased:
roles:
global:
- name: "my_okta_group"
permissions:
- "Overall/Administer"
I see this properly getting converted into $JENKINS_HOME/config.xml.
What I don't specify, but seems to be required, is assignments:, because - it's RBAC after all, and the user assignments into roles should be made in Okta, not Jenkins.
After browsing the plug-in code, it appears hard-wired for an explicit user SID list to be specified in the JCasC. That's not going to work for me.
Is there a different way to use this plug-in to achieve the goal?
Is there another RBAC plug-in that would work better?

The above is very close to a working solution. assignments: is indeed required, and it supports username or group. Also the 'name' of 'authorizationStrategy.roleBased.roles' is the Jenkins role name, not the OIDC group name.
The oic-auth configuration maps OIDC token fields to Jenkins user properties, and then the role-strategy checks for the OIDC token's username, as well as its group(s).
My working config is:
jenkins:
securityRealm:
oic:
clientId: "${clientId}"
clientSecret: "${clientSecret}"
wellKnownOpenIDConfigurationUrl: "${oidcIssuerUrl}/.well-known/openid-configuration"
userInfoServerUrl: "${oidcIssuerUrl}/oauth2/v1/userinfo"
tokenFieldToCheckKey: ""
tokenFieldToCheckValue: ""
fullNameFieldName: "name"
groupsFieldName: "groups"
disableSslVerification: false
logoutFromOpenidProvider: true
endSessionEndpoint: "${oidcIssuerUrl}/oauth2/v1/logout"
postLogoutRedirectUrl: "https://${dns_name_full}"
escapeHatchEnabled: false
escapeHatchUsername: ""
escapeHatchSecret: "my-unused-password"
escapeHatchGroup: ""
automanualconfigure: "auto"
emailFieldName: "email"
userNameField: "name"
tokenServerUrl: "${oidcIssuerUrl}/oauth2/v1/token"
authorizationServerUrl: "${oidcIssuerUrl}/oauth2/v1/authorize"
scopes: "address phone openid profile offline_access groups email"
authorizationStrategy:
roleBased:
roles:
global:
- name: "my_jenkins_role"
permissions:
- "Overall/Administer"
assignments:
- "my_okta_group"
BTW, I specify the yaml with Helm:
...
JCasC:
configScripts:
okta: |
jenkins:
securityRealm:
...

Related

Slack bot scope not updating

I created a Slack bot using the "New App". Set it as a bot and am using the "OAuth Tokens for Your Workspace". With the following scopes under "Bot token scopes":
app_mentions:read
chat:write
chat:write.customize
files:read
files:write
groups:write
I added some of these permissions after the initial install (if it matters and you have to refresh something?). The bot is installed to a workspace and I have invited it to a private channel.
Using the example of the Slack API documentation:
from slack_sdk import WebClient
from slack_sdk.errors import SlackApiError
slack_token = SLACK_TOKEN # xoxb-....
client = WebClient(token=slack_token)
try:
"""
response = client.files_upload(
channels="C040W4L2HA6",
file="test.txt",
title="Test upload"
)
"""
response = client.chat_postMessage(
channel="C040W4L2HA6",
text="Hello from your app! :tada:"
)
except SlackApiError as e:
# You will get a SlackApiError if "ok" is False
assert e.response["error"]
For both the file write and message examples I get: "ok":false,"error":"missing_scope","needed":"chat:write:bot","provided":"app_mentions:read" but "needed" changes from "chat:write:bot" to "file:write" if I run that part.
Few issues here. I am using the newest version of the client with Python 3.9 and it asks for a permission that is depricated (write:bot is just write now). In both cases it is as if my only active scope is app_mentions:read, nothing else. When I added the other scopes, I clicked "Request to install" and the person reviewing that accepted.
YAML config:
display_information:
name: BotName
description: Bot desc.
background_color: "#000000"
features:
bot_user:
display_name: botname
always_online: false
oauth_config:
scopes:
user:
- chat:write
bot:
- app_mentions:read
- chat:write
- files:write
- files:read
- groups:write
- chat:write.customize
settings:
interactivity:
is_enabled: true
org_deploy_enabled: false
socket_mode_enabled: true
token_rotation_enabled: false
Any ideas?
Under "Install app" I had to reinstall it to the workspace, it was not done automatically.

AWS CDK: lambda permissions and EFS mount

I am trying to declare in my stack a lambda function with an EFS mount.
The lambda has a custom execution role with arn
arn:aws:iam::ACCOUNTID:role/service-role/ROLENAME
i.e. it was created in the stack using
lambda_role = aws_iam.Role(..., path="/service-role/", ...)
The code snippet declaring the lambda is
_lambda.Function(
self,
id="myId",
runtime=_lambda.Runtime.PYTHON_3_8,
code=_lambda.Code.asset('lambda'),
handler='my_module.lambda_handler',
role=lambda_role,
function_name="function-name",
timeout=core.Duration.seconds(30),
vpc=vpc,
filesystem=_lambda.FileSystem.from_efs_access_point(access_point, '/efs')
)
The deployment fails with this error:
API: iam:PutRolePolicy User: USERNAME is not authorized to perform: iam:PutRolePolicy on resource: role service-role with an explicit deny
That "role service-role" in the error message seemed weird, so I inspected the synthesized CF template, and noticed this section:
lambdarolePolicy2FC0B982:
Type: AWS::IAM::Policy
Properties:
PolicyDocument:
** policy giving elasticfilesystem:ClientWrite and elasticfilesystem:ClientMount permissions**
PolicyName: lambdarolePolicy2FC0B982
Roles:
- Fn::Select:
- 1
- Fn::Split:
- /
- Fn::Select:
- 5
- Fn::Split:
- ":"
- Fn::ImportValue: sgmkr-iam-arn-mr
That ImportValue maps to the arn of the lambda execution role. The problem I see is with the string manipulation, which does not seem to take into account the fact that the role has a path. The result of that chain of Select/Split is indeed "service-role", not the proper role name.
I have two questions:
why is CDK trying to add extra permissions to a role I defined? I already added the needed permissions to the relevant role, and I really don't want anything added to it. Moreover, in my setup, iam:PutRolePolicy calls are strictly regulated, so this would almost certainly fail. That's the very reason I pass my own role. How can I switch off this automatic policy generation?
why is CDK ignoring the role path? Is this intended?
Thanks for your help,
Andrea.
The easiest workaround would I could think of would be using "role name" instead "role ARN".
Instead
role_arn = iam.Role.from_role_arn(self, "Role", role_arn=<role_arn>)
Use:
role_name = iam.Role.from_role_name(self, "Role", role_name=<role_name>)

Websphere 8.5.5.16, OIDC IDToken - user problem

I'm trying to configure Oauth authorization on websphere 8.5.5.16. I added interceptor with issuerIdentifier parameter = https://company.com/abc I next step I added trust external realm: https://company.com/abc And when I try to start service in my app (IBM BPM) I getting an error: NullPointer Exception. Please look at the logs on how the user is created:
Principal: https://company.com/abc/login_user
Public Credential: com.ibm.ws.security.auth.WSCredentialImpl#ebc4e0d2
Private Credential: {setLtpaCookie=false, com.ibm.wsspi.security.cred.securityName=login_user, com.ibm.wsspi.security.cred.uniqueId=user:https://company.com/abc/login_user, token_type=, access_token=xxx, id_token=, com.ibm.wsspi.security.cred.realm=https://company.com/abc, com.ibm.wsspi.security.cred.groups=[], refresh_token=, JsonWebToken=JsonWebToken:{"aud":"0000","iss":"https://company.com/abc","iat":122,"nbf":123,"exp":232,"auth_time":222,"nonce":"aaa","sub":"ddddd/fffff","upn":"login_user","unique_name":"domain\\login_user","pwd_url":"https://company.com/abc/portal/updatepassword/","pwd_exp":"4545","sid":"S-1-5-21-66-117609710","authorities":["Group_1, Group_2"],"given_name":"Name","family_name":"Surname","apptype":"Public","appid":"0000","authmethod":"http://schemas.microsoft.com/ws/2008/06/identity/authenticationmethod/windows","ver":"1.0","scp":"openid"}}
Private Credential: com.ibm.ws.security.token.SingleSignonTokenImpl#347c9d2b
Private Credential: com.ibm.ws.security.token.AuthenticationTokenImpl#718ea698
Private Credential: com.ibm.ws.security.token.AuthorizationTokenImpl#27e8a5bb
00000187 UserOrgModule 1 com.lombardisoftware.userorg.UserOrgModule getIdFromPrincipalName getIdFromPrincipalName() user=/company.com/abc/login_user, id=null
user = /company.com/abc/login_user not: login_user Why? Please help.
From message "00000187 UserOrgModule", I can tell your BPM application can not help realm name that contains '/' character. You can resolve the problem with following steps:
In your TAI properties, add useRealm property, and give an unique and meaningful value as realm, for example,
provider_.useRealm=abc123
Add "abc123" as trusted realm. This value matches value you define in step 1.
If you assign roles to users unique id, you need reassign roles again with unique id build from this new realm.
Thanks. I did exactly as you wrote.
I added in my interceptor config: provider_1.useRealm=myrealm
I added trusted realm in Global security > Federated repositories > Trusted authentication realms - inbound (Name = myrealm, Trusted).
I restarted server.
Nothing has changed. I still see: user=/company.com/abc/login_user, id=null because in JWT token, in iss field I have value: 'https://company.com/abc' and unfortunately I cannot change this

How to get standards claims of the openid scope "profile" from the ADFS server?

I want the standard openid claims from the scope profile with the ADFS service on Windows 20016.
My request call look like:
https://myserver/adfs/oauth2/authorize?
response_type=code&
client_id=123456&
redirect_uri=http://localhost/bar&
scope=openid%20email%20profile
The id_token contains the follow:
{
aud=123456,
sub=xyz,
upn=bob#company.local,
unique_name=COMPANY\bob,
auth_time=1518686971,
iss=https://adfs.company.local/adfs,
exp=1518690571,
iat=1518686971,
sid=S-1-5-21-123-456-789-098
}
The app was registered with the powershell line:
Add-AdfsClient -Name "foo" -ClientId "123456" -RedirectUri #("http://localhost/")
How can I get the claims like email, given_name and family_name?
Have you tried configuring this with the wizard because you can define claims rules on the Web API?
If that doesn't suit, have a look here at some examples.

How to config phabricator login use ldap?

I have already migrate Jenkins to use LDAP login, and have no problem.
But when I tried to migrate phabricator to use LDAP, I got "Username or password are incorrect." every time, and I'm sure the same username and passwd can login Jenkins. I was using the same OpenLDAP server, and the LDAP has a readonly DN: cn=readonly,dc=my-company,dc=com. Phabricator configurations list below:
Allow: "Allow Login"
LDAP Hostname & Port: exactly the same with my Jenkins configuration
Base Distinguished Name: ou=user,dc=my-company,dc=com (while Jenkins root DN was dc=my-company,dc=com)
Search Attributes: empty
Always Search: unchecked
Anonymous Username: cn=readonly, dc=my-company, dc=com (same with Jenkins Manager DN)
Anonymous Password: the password (same with Jenkins Manager password)
Username Attribute: uid
Realname Attributes: empty
LDAP Version: 3
This has block me two days, is there something I missed?
Thanks for your answer~
Oh, I figure it out. Phabricator has a different LDAP login mechanism with Jenkins. Phabricator always bind LDAP with the user's DN and password (to verify login), then search the user's DN itself. Below is the comment in the LDAP login code:
// This is unusual (since the bind succeeded) but we've seen it at least
// once in the wild, where the anonymous user is allowed to search but
// the credentialed user is not.
// If we don't have anonymous credentials, raise an explicit exception
// here since we'll fail a typehint if we don't return an array anyway
// and this is a more useful error.
// If we do have anonymous credentials, we'll rebind and try the search
// again below. Doing this automatically means things work correctly more
// often without requiring additional configuration.
So, LDAP users must have search acl, like:
olcAccess: {1}to *
by self write
by dn="cn=admin,dc=my-company,dc=com" write
by dn="cn=readonly,dc=my-company,dc=com" read
by users search
by * none
I didn't have 'by users search' option, so login failed.

Resources