Nexus3 Groovy script to add role using External Role mapping from LDAP - nexus

I'm working with Nexus3 groovy scripting to Provision/Bootstrap my Nexus3 - OSS instance. While looking through the complex scripting examples and the shell scripting examples as well as the sonatype books, i'm not seeing any clear documentation about the security method and it's parameters.
My main question is how do I map an LDAP group to a Nexus Role using groovy?
security.addRole('admin.role', 'Admin', 'Some Description', 'nx-admin', 'LDAPGroupName')
I'm getting a 400 with this when pushing to Nexus and running. I appreciate any help I can get here.

I think, it's bit a late update.
It seems , you are passing up the wrong parameter type for privilege and role.
I'd suggest you try below :-
security.addRole('admin.role', 'Admin', 'Some Description', ['nx-admin'], ['LDAPGroupName'])

The script below adds mapping from LDAP role to nexus role.
import groovy.json.JsonOutput
import groovy.json.JsonSlurper
import org.sonatype.nexus.security.SecuritySystem
def request = new JsonSlurper().parseText(args)
String ldap = request.ldap
String name = request.name ?: request.ldap
String nexus = request.nexus
assert ldap != null && nexus != null
def role = security.addRole(ldap, name, "Mapping for LDAP "+ldap, [], [nexus]);
JsonOutput.prettyPrint(JsonOutput.toJson(role))
The parameter 'ldap' is LDAP role name and 'nexus' is nexus role name (like 'nx-admin'). Note after adding mapping two roles with the same id will appear (one for LDAP source, other for default). Nexus apparently correlate them by id. Script below lists all roles (LDAP and default one). You might need to pass user LDAP user name to this script in order to LDAP roles to appear, because LDAP is deactivated if it is not used for some time, in that case script will show only nexus roles.
import groovy.json.JsonOutput
import groovy.json.JsonSlurper
import org.sonatype.nexus.security.SecuritySystem
SecuritySystem securitySystem = container.lookup(SecuritySystem.class.name)
if(args != null && args.length() > 0) {
def request = new JsonSlurper().parseText(args)
if(request.user != null && request.user.length() > 0) {
securitySystem.getUser(request.user)
}
}
JsonOutput.prettyPrint(JsonOutput.toJson(securitySystem.listRoles()))

Related

Setup programmatically the language code to send translated email verification - ns+angular app

I'm using this plugin: https://docs.nativescript.org/plugins/firebase-auth.html
to integrate my nativescript+angular mobile app with firebase authentication system.
Is there any way to setup the language code to send a translated email verification (template provided already by firebase) ?
I tried to setup by doing that
import { firebase } from '#nativescript/firebase-core'
import '#nativescript/firebase-auth'
...
let authFirebase = firebase().auth()
authFirebase.languageCode = 'fr'
authFirebase
.createUserWithEmailAndPassword(useremail, userpassword)
.then((cred) => {
if (cred && !cred.user.emailVerified) {
// send the account activation email
cred.user.sendEmailVerification()
}
})
but I got immediately a compilation error:
Cannot assign to 'languageCode' because it is a read-only property.ts(2540)
Any suggestion?
Many thanks in advance

How to fetch the viewid from google analytics by giving the access_token using python

After successful login from the consent screen, I am getting the access_token now the next step is to fetch all the view id from the google analytics account.Please help me out
Example: This is the access_token("ya29.A0ARrdaM8IvLg8jjVHWgxneSp_mxgFYHpKt4LwPGZEVqzOphMA2Cll6mjMxlQRFanbJHh1WrBEYVe2Y1BvBU6j7h_17nVeY4h-FWdUuv5bo0rzETTz_-xw4t5ZNBYpj26Cy3u4Y1trZnqVIA4")
You should check the Managment api quickstart python
"""A simple example of how to access the Google Analytics API."""
import argparse
from apiclient.discovery import build
import httplib2
from oauth2client import client
from oauth2client import file
from oauth2client import tools
def get_service(api_name, api_version, scope, client_secrets_path):
"""Get a service that communicates to a Google API.
Args:
api_name: string The name of the api to connect to.
api_version: string The api version to connect to.
scope: A list of strings representing the auth scopes to authorize for the
connection.
client_secrets_path: string A path to a valid client secrets file.
Returns:
A service that is connected to the specified API.
"""
# Parse command-line arguments.
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
parents=[tools.argparser])
flags = parser.parse_args([])
# Set up a Flow object to be used if we need to authenticate.
flow = client.flow_from_clientsecrets(
client_secrets_path, scope=scope,
message=tools.message_if_missing(client_secrets_path))
# Prepare credentials, and authorize HTTP object with them.
# If the credentials don't exist or are invalid run through the native client
# flow. The Storage object will ensure that if successful the good
# credentials will get written back to a file.
storage = file.Storage(api_name + '.dat')
credentials = storage.get()
if credentials is None or credentials.invalid:
credentials = tools.run_flow(flow, storage, flags)
http = credentials.authorize(http=httplib2.Http())
# Build the service object.
service = build(api_name, api_version, http=http)
return service
def get_first_profile_id(service):
# Use the Analytics service object to get the first profile id.
# Get a list of all Google Analytics accounts for the authorized user.
accounts = service.management().accounts().list().execute()
if accounts.get('items'):
# Get the first Google Analytics account.
account = accounts.get('items')[0].get('id')
# Get a list of all the properties for the first account.
properties = service.management().webproperties().list(
accountId=account).execute()
if properties.get('items'):
# Get the first property id.
property = properties.get('items')[0].get('id')
# Get a list of all views (profiles) for the first property.
profiles = service.management().profiles().list(
accountId=account,
webPropertyId=property).execute()
if profiles.get('items'):
# return the first view (profile) id.
return profiles.get('items')[0].get('id')
return None
def get_results(service, profile_id):
# Use the Analytics Service Object to query the Core Reporting API
# for the number of sessions in the past seven days.
return service.data().ga().get(
ids='ga:' + profile_id,
start_date='7daysAgo',
end_date='today',
metrics='ga:sessions').execute()
def print_results(results):
# Print data nicely for the user.
if results:
print 'View (Profile): %s' % results.get('profileInfo').get('profileName')
print 'Total Sessions: %s' % results.get('rows')[0][0]
else:
print 'No results found'
def main():
# Define the auth scopes to request.
scope = ['https://www.googleapis.com/auth/analytics.readonly']
# Authenticate and construct service.
service = get_service('analytics', 'v3', scope, 'client_secrets.json')
profile = get_first_profile_id(service)
print_results(get_results(service, profile))
if __name__ == '__main__':
main()

ASAuthorizationAppleIDRequest with name and mail scope returns nil values

I'm implementing Sign in with Apple and noticed that the email and fullName properties of the returned ASAuthorizationAppleIDCredential are only filled on the very first Sign-In for this Apple ID. On all subsequent Sign-Ins those properties are nil.
Is this a bug on iOS 13 or expected behaviour?
Here is the code I'm using to start the request:
#available(iOS 13.0, *)
dynamic private func signInWithAppleClicked() {
let request = ASAuthorizationAppleIDProvider().createRequest()
request.requestedScopes = [.fullName, .email]
let controller = ASAuthorizationController(authorizationRequests: [request])
controller.delegate = self
controller.presentationContextProvider = self
controller.performRequests()
}
I'm receiving the credential in this delegate method:
public func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
guard let credential = authorization.credential as? ASAuthorizationAppleIDCredential else { return }
let userIdentifier = credential.user
let token = credential.identityToken
let authCode = credential.authorizationCode
let realUserStatus = credential.realUserStatus
let mail = credential.email // nil
let name = credential.fullName // nil
}
Seems like a bug but after reading different posts on apple forums it looks like this seems to be the expected behaviour.
So some takeaways.
On the first time sign in with apple (signup) make sure to create user account on your backend.
In case of any connection error with your servers, make sure you save the user details locally (because you are not getting this next time) and keep retrying to create account on your backend.
For testing on device you can revoke your apple ID login for your app. After revoking it will work like a signup next time and you will get the details like (email, name, etc).
To revoke access on your device with IOS 13.
iPhone Settings > Apple Id > Password & Security > Apple ID logins > {YOUR APP} > Stop using Apple ID
In case you're wondering how to retrieve email second and subsequent times, here's a hint: use identityToken which contains encoded in JWT user authorisation data including email.
Import this library to decode JWT: https://github.com/auth0/JWTDecode.swift
try this code
import JWTDecode
// ...
if let identityTokenData = appleIDCredential.identityToken,
let identityTokenString = String(data: identityTokenData, encoding: .utf8) {
print("Identity Token \(identityTokenString)")
do {
let jwt = try decode(jwt: identityTokenString)
let decodedBody = jwt.body as Dictionary<String, Any>
print(decodedBody)
print("Decoded email: "+(decodedBody["email"] as? String ?? "n/a") )
} catch {
print("decoding failed")
}
Or decode it at PHP backend like this:
print_r(json_decode(base64_decode(str_replace('_', '/', str_replace('-','+',explode('.', $identityTokenString)[1])))));
It is a correct behavior when implementing SignIn with Apple.
This behaves correctly, user info is only sent in the
ASAuthorizationAppleIDCredential upon initial user sign up. Subsequent
logins to your app using Sign In with Apple with the same account do
not share any user info and will only return a user identifier in the
ASAuthorizationAppleIDCredential. It is recommended that you securely
cache the initial ASAuthorizationAppleIDCredential containing the user
info until you can validate that an account has successfully been
created on your server.
To overcome this issue we can store all the required information in Keychain. I have created Singleton class for SignIn With Apple. I am sure it will help you.
Git source: https://github.com/IMHitesh/HSAppleSignIn
You need to follow below steps:
Step:1
Add the AppleSignIn folder into your project.
Step:2
Enable SignIn with Apple in Capabilities.
Step:3 -> IMPORTANT
Goto your UIViewController and Add Container view for SignIn with
apple.
if #available(iOS 13.0, *) {
appleSignIn.loginWithApple(view:viewAppleButton, completionBlock: { (userInfo, message) in
if let userInfo = userInfo{
print(userInfo.email)
print(userInfo.userid)
print(userInfo.firstName)
print(userInfo.lastName)
print(userInfo.fullName)
}else if let message = message{
print("Error Message: \(message)")
}else{
print("Unexpected error!")
}
})
}else{
viewAppleButton.isHidden = true
}
This seems to be the expected behaviour:
This behaves correctly, user info is only sent in the
ASAuthorizationAppleIDCredential upon initial user sign up. Subsequent
logins to your app using Sign In with Apple with the same account do
not share any user info and will only return a user identifier in the
ASAuthorizationAppleIDCredential. It is recommened that you securely
cache the initial ASAuthorizationAppleIDCredential containing the user
info until you can validate that an account has succesfully been
created on your server.
Source https://forums.developer.apple.com/thread/121496#379297
This is not bug but it will indicate that your authentication successfully store to your device setting.
if you want to that all information again then you need to following this states.
go to your device -> Settings -> Apple ID -> Password & Security
-> Apps Using your Apple ID -> you get list of apps used sign in with apple {find your app} -> swift left of your apps row {show Delete option} -> click on Delete
restart your app or repress sign in with apple button
Now you can get all information
In https://developer.apple.com/documentation/signinwithapplerestapi/authenticating_users_with_sign_in_with_apple it says:
Because the user’s information isn’t shared with your app in any subsequent API calls, your app should store it locally, immediately after you receive it from the API response. In case of subsequent failures in your process or network, you can read the information from local storage and try processing it again.
The email would be given on the first time sign in. If the user do not "revoke" the apple sign in of your app (which is in the user's Apple ID of system setting page) the callback for signing in would be returned with a nil email value. You could save the user id and email info of the first time sign-in successful result, and when the next time sign in to judge the difference between the return and the saved info.
A better practice is to judge the the value of ASAuthorizationAppleIDProvider.getCredentialState while your app is being "active" for syncing the sign-in state with back-end server in time.
Please refer to: How to Sign Out of Apple After Being Authenticated
I wrote a Helper class specific for this issue. This Helper class can help to save and retrieve the user info securely to and from keyChain.
I am using SwiftKeychainWrapper library to do the heavy task for me. Feel free to copy paste the helper class in your code.You might need to add any other extra information depending on your need.
import Foundation
import SwiftKeychainWrapper
/// A Helper class which abstract Keychain API related calls.
final class KeyChainService {
// MARK: - Properties
static let shared = KeyChainService()
/// Returns previous saved user name if available.
var appleUserName: String? {
return KeychainWrapper
.standard
.string(forKey: .appAppleUserName)
}
/// Returns previous saved user appleId/email if available.
var appleUserEmail: String? {
return KeychainWrapper
.standard
.string(forKey: .appAppleEmailId)
}
/// Saves the apple user name into keychain.
/// - Parameter name: Apple user name retrieved form AppleLogin.
/// - Returns: true if succeed otherwise false.
#discardableResult
func saveAppleUserName(name: String?) -> Bool {
guard let name = name else {return false}
return KeychainWrapper.standard.set(
name,
forKey: KeychainWrapper.Key.appAppleUserName.rawValue
)
}
/// Saves the apple user email into keychain.
/// - Parameter email: Apple userId/email retrieved form AppleLogin.
/// - Returns: true if succeed otherwise false.
#discardableResult
func saveAppleEmail(email: String?) -> Bool {
guard let email = email else {return false}
return KeychainWrapper.standard.set(
email,
forKey: KeychainWrapper.Key.appAppleEmailId.rawValue
)
}
/// Deletes both apple user name and saved Id from keyChain.
func deleteSavedAppleUserInfo(){
KeychainWrapper.standard.remove(forKey: .appAppleUserName)
KeychainWrapper.standard.remove(forKey: .appAppleEmailId)
}
}
// MARK: - KeychainWrapper + Extensions
extension KeychainWrapper.Key {
/// A random string used to identify saved user apple name from keychain.
static let appAppleUserName: KeychainWrapper.Key = "appAppleUserName"
/// A random string used to identify saved user apple email /Id from keychain.
static let appAppleEmailId:KeychainWrapper.Key = "appAppleEmailId"
}

Endpoint belongs to different authority

trying to use Azure AD as OpenID provider with IdentityModel package
However the problem is that it produces wrong endpoint configuration
var client = new HttpClient();
const string identityUrl = "https://login.microsoftonline.com/00edae13-e792-4bc1-92ef-92a02ec1d939/v2.0";
const string restUrl = "https://localhost:44321";
var disco = await client.GetDiscoveryDocumentAsync(identityUrl);
if (disco.IsError)
{
Console.WriteLine(disco.Error);
return;
}
returns error
Endpoint belongs to different authority:
https://login.microsoftonline.com/00edae13-e792-4bc1-92ef-92a02ec1d939/oauth2/v2.0/authorize
openid-configuration output is
{"authorization_endpoint":"https://login.microsoftonline.com/00edae13-e792-4bc1-92ef-92a02ec1d939/oauth2/v2.0/authorize",
"token_endpoint":"https://login.microsoftonline.com/00edae13-e792-4bc1-92ef-92a02ec1d939/oauth2/v2.0/token" ... }
oauth2 is added between the tenatID and version. I suppose this is why openid metadata validation fails.
Is it possible to configure AzureAD to return correct metadata for the openid-configuration ?
Regards
could you find a solution for this? The only way I could figure out (far to be the optimal solution) is to add the endpoints to a list of additional endpoint base addresses. Otherwise you have to set the validations to false as stated in the comments above.
var client = httpClientFactory.CreateClient();
var disco = await client.GetDiscoveryDocumentAsync(
new DiscoveryDocumentRequest
{
Address = "https://login.microsoftonline.com/00edae13-e792-4bc1-92ef-92a02ec1d939/v2.0",
Policy =
{
ValidateIssuerName = true,
ValidateEndpoints = true,
AdditionalEndpointBaseAddresses = { "https://login.microsoftonline.com/00edae13-e792-4bc1-92ef-92a02ec1d939/oauth2/v2.0/token",
"https://login.microsoftonline.com/00edae13-e792-4bc1-92ef-92a02ec1d939/oauth2/v2.0/authorize",
"https://login.microsoftonline.com/00edae13-e792-4bc1-92ef-92a02ec1d939/discovery/v2.0/keys",
"https://login.microsoftonline.com/00edae13-e792-4bc1-92ef-92a02ec1d939/oauth2/v2.0/devicecode",
"https://graph.microsoft.com/oidc/userinfo",
"https://login.microsoftonline.com/00edae13-e792-4bc1-92ef-92a02ec1d939/oauth2/v2.0/logout"
}
},
}
);
If you take a look at the code inside IdentityModel repository, you can see that the default validation of the endpoints validates them by doing a "starts with" method. https://github.com/IdentityModel/IdentityModel/blob/1db21e2677de6896bc11227c70b927c502e20898/src/Client/StringComparisonAuthorityValidationStrategy.cs#L46
Then the only two required AdditionalEndpointBaseAddresses inside the DiscoveryDocumentRequest Policy field you need to add are "https://login.microsoftonline.com/<guid>" and "https://graph.microsoft.com/oidc/userinfo".
I had the same problem as well and when i upgraded IdentityModel to version 2.16.1 the problem was solved
Azure AD seems to need Additional Endpoints configuration as #flacid-snake suggested. Setting validate endpoints to False is a security threat and should be avoided.
The best way is to make it configurable, preferable in the UI when you configure the SSO server. Endpoints can change and they should be easy to change. It will also make it easier if you later decide to support Okta or other providers and they require additional endpoints.
As of June 2021 you also need to include Kerberos endpoint like:
https://login.microsoftonline.com/888861fc-dd99-4521-a00f-ad8888e9ecc8bfgh/kerberos (replace with your directory tenant id).

Using flask_login and flask-JWT together in a REST API

I am new to flask, recently learned about flask_security/flask_login/flask_user.
I wish that somehow I could use flask_login along with flask-JWT, for the REST API.
Basically, I'd like to have the features like remember-me, forgot-password etc, from the flask_login
Upon searching, I found that it couldn't be done on the same flask view.
Could somebody guide me, how to do it?
Thanks.
flask-login provides the request_loader callback exactly for this purpose, for authenticating requests in a custom way.
In my case, I added this to my create_app function:
#login_manager.request_loader
def load_user_from_request(request):
auth_headers = request.headers.get('Authorization', '').split()
if len(auth_headers) != 2:
return None
try:
token = auth_headers[1]
data = jwt.decode(token, current_app.config['SECRET_KEY'])
user = User.by_email(data['sub'])
if user:
return user
except jwt.ExpiredSignatureError:
return None
except (jwt.InvalidTokenError, Exception) as e:
return None
return None
Otherwise, I followed this tutorial, so the token is created like this (in the login function):
token = jwt.encode({
'sub': user.email,
'iat':datetime.utcnow(),
'exp': datetime.utcnow() + timedelta(minutes=30)},
current_app.config['SECRET_KEY'])
This way you can just use #login_required from flask-login instead of defining a custom decorator to protect views.
I used PyJWT instead of Flask-JWT since it seems Flask-JWT is discontinued.

Resources