How can pass username password as attributes in SAML Request as shown in the code below. I'm using lastpass-saml-sdk.jar to communicate with the GLUU IDP server.
SAMLInit.initialize();
String dir = Constants.METADATA_LOCATION;
if (dir == null)
throw new SAMLException("Unable to locate SAML metadata");
IdPConfig idpConfig = new IdPConfig(new File(dir + "\\gluu-idp-metadata.xml"));
SPConfig spConfig = new SPConfig(new File(dir + "\\sp-meta.xml"));
SAMLClient client= new SAMLClient(spConfig, idpConfig);
// when a login link is clicked, create auth request and
// redirect to the IdP
String requestId = SAMLUtils.generateRequestId();
String authrequest = client.generateAuthnRequest(requestId);
String url = client.getIdPConfig().getLoginUrl() +
"?SAMLRequest=" + URLEncoder.encode(authrequest, "UTF-8");
// redirect to url...
response.sendRedirect(url);
You do not pass username and passord directly to the Identity Provider. After you have redirected the user, the user himself will enter username and password at the IDP.
Here is one of my blog posts describing the flow in SAML Web rowser profile.
Related
Recently I integrated superset with my web application so that when an user who is authenticated by my web application can enter superset and view/edit/create dashboards based on their role just by clicking the link no need to even login. For doing this I had to bypass the login for which I referred this article.
Custom SecurityManager I used to bypass login
class CustomAuthDBView(AuthDBView):
#expose('/login/', methods=['GET', 'POST'])
def login(self):
redirect_url = self.appbuilder.get_url_for_index
user_name = request.args.get('username')
user_role = request.args.get('role')
if user_name is not None:
user = self.appbuilder.sm.find_user(username=user_name)
if not user:
role = self.appbuilder.sm.find_role(user_role)
user = self.appbuilder.sm.add_user(user_name, user_name, 'last_name', user_name + "#domain.com", role, password = "password")
if user:
login_user(user, remember=False)
return redirect(redirect_url)
else:
print('Unable to auto login', 'warning')
return super(CustomAuthDBView,self).login()
class CustomSecurityManager(SupersetSecurityManager):
authdbview = CustomAuthDBView
def __init__(self, appbuilder):
super(CustomSecurityManager, self).__init__(appbuilder)
So according to above code using url http://localhost:8088/login?username=John will login the user John internally or if user John does not exist account is created with some role which is based on the role of user in my web application
Now the problem is anyone who can guess this url http://localhost:8088/login?username=USER_NAME can create their account in superset, so how to protect or secure this '/login' endpoint
You can use the API so that you dont expose request details over the URL.
from flask_appbuilder.api import BaseApi, expose
from . import appbuilder
class LoginApi(BaseApi):
resource_name = "login"
#expose('/loginapi/', methods=['GET','POST'])
##has_access
def loginapi(self):
if request.method == 'POST':
username = request.json['username']
password = request.json['password']
appbuilder.add_api(LoginApi)
I have a web app. I'm trying to get it to authenticate against a Win2012 R2 ADFS server.
I have the relying party set up, get redirected, sign in, then redirected back to the app as a failed request.
In the event log I have this:
MSIS7070: The SAML request contained a NameIDPolicy that was not satisfied by the issued token. Requested NameIDPolicy: AllowCreate: True Format: urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress SPNameQualifier: . Actual NameID properties: null.
If I read this right, the webapp is asking for urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress but that policy isn't found for the relying party.
Under the relying party, I have two rules:
# get email address from active directory
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"]
=> issue(store = "Active Directory",
types = ("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"), query = ";mail;{0}", param = c.Value);
rule 2
transform email address to nameid/email
c:[Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"]
=> issue(Type = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
Issuer = c.Issuer,
OriginalIssuer = c.OriginalIssuer,
Value = c.Value,
ValueType = c.ValueType,
Properties["http://schemas.xmlsoap.org/ws/2005/05/identity/claimproperties/format"]
= "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress");
I've double checked and made sure that the formats match, but I'm stuck on the error messages.
I have simple app that is trying to do a http web request to a server that requires SAML authentication. Authenticated users will get a http response header with a special token, which is what I need to ultimately get.
My app is .net based and does a pretty simple http web request. It does the request then parses the response header. I later traverse the header for the specific token I need:
...
try
{
WindowsIdentity identity = HttpContext.User.Identity as WindowsIdentity;
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.UseDefaultCredentials = true;
req.AllowAutoRedirect = true;
req.Timeout = 30000;
HttpWebResponse response = (HttpWebResponse)req.GetResponse();
if (response == null)
{
throw new Exception("No HTTP Response");
}
StringBuilder sb = new StringBuilder();
Byte[] buffer = new byte[8192];
Stream rStream = response.GetResponseStream();
int count = 1;
do
{
count = rStream.Read(buffer, 0, buffer.Length);
if (count != 0)
{
sb.Append(Encoding.UTF8.GetString(buffer, 0, count));
}
} while (count > 0);
...
The problem is that the server I'm requesting requires SAML authentication. It redirects to an ADFS server upon request. My app server currently uses kerberos authentication but I can enable it to do SAML as well. Both servers use the same IdP (ADFS) and are in the same enterprise.
My question is - since my app can also do SAML on the same IdP, is there anyway I could get the necessary claims to connect directly into the destination server?
I have followed the blog http://blogs.msdn.com/b/exchangedev/archive/2015/01/22/building-demon-or-service-apps-with-office-365-mail-calendar-and-contacts-apis-oauth2-client-credential-flow.aspx to create a daemon application . I am able to get the app only token for the domain in which i have registered the application . But when I try to get for other organizations it throws an error
"
{"error":"invalid_client","error_description":"AADSTS70002: Error validating cre
dentials. AADSTS50012: Client assertion audience claim does not match Realm issu
er.\r\nTrace ID: 09e025f5-7db9-46c3-9df9-574c6820a011\r\nCorrelation ID: f4d0fa5
7-ee8c-4443-b28b-d372d945f81f\r\nTimestamp: 2015-05-04 13:51:51Z","error_codes":
[70002,50012],"timestamp":"2015-05-04 13:51:51Z","trace_id":"09e025f5-7db9-46c3-
9df9-574c6820a011","correlation_id":"f4d0fa57-ee8c-4443-b28b-d372d945f81f","subm
it_url":null,"context":null}"
But i have configured the application to be multi tenant .
this is the request i make
request https://login.windows.net/<tenantId>/oauth2/to
ken
grant_type=client_credentials
redirect_uri=http://localhost.com:9000
resource=https://outlook.office365.com/
client_assertion_type =urn:ietf:params:oauth:client-assertion-type:jwt-bearer
client_assertion="eyJhbGciOiJSUzI1NiIsIng1dCI6IjZlLzEra01scHhuTHArZFJ4d1BqS21EdmZCQT0ifQ.eyJhdWQiOiJodHRwczovL2xvZ2luLndpbmRvd3MubmV0L2ZmNjQxNTFmLTIwM2EtNGM0MC1hZDcxLTExOTE2YjY2Yzg3My9vYXV0aDIvdG9rZW4iLCJleHAiOjE0MzEwMDYzMDMsImlzcyI6ImFkMTkzY2I1LWU2NmUtNDdmNS1iMTc4LTQxM2NlODA3ZDg2YiIsImp0aSI6IjMyMDZiYWI5LTVmYmUtNDA3ZS02OWY2LTJlNGRjNDQ3NzQxYSIsIm5iZiI6MTQzMTAxMTMwMywic3ViIjoiYWQxOTNjYjUtZTY2ZS00N2Y1LWIxNzgtNDEzY2U4MDdkODZiIn0.eEOlhsl-vbdzIiV3AfGFOH187Yb8zpGSGm6RbMhDX4NRJbwOWjJr3eFK3rGXSkl1vhSfJ_oFc69pB1AGfUK8u_SWRl7U3GgH3EJryE-FiVluCQ-ONZ3Qj1u6VggXgTodi0bdvhQF4WlwazXmJGbpeVRUZBm2rlTcd8JtQY96sOu1CRDpZJOFnHzjqleVdrnw8_pNVUafwlnaosRT9tOIgiK9apjN_KY5JMM1QTYKhKk5ZApjmr8agTZpObdz-_Y9znjaSxQcYkFnQeCGc-qwISzH1OqG_7JbCDq6Dp1-oBU5sJneJaF6IxX8-sWyaju3ntMWQyINeuHnRCoPrlp2tg"
this is the assertion i create
token.Header["alg"] = "RS256"
token.Header["x5t"] = "thumbprint of certificate "
token.Claims["aud"] = "https://login.windows.net/" + TenantId + "/oauth2/token"
token.Claims["exp"] = time.Now().Add(time.Hour * 72).Unix()
token.Claims["iss"] = client_id
token.Claims["jti"] = some guid
token.Claims["nbf"] = (time.Now().Add(time.Hour * 72).Unix()) + 5000
token.Claims["sub"] = client_id
please let me what to be done so that i can get the access token for other organiztion's domain .
Thanks in advance
I am trying to use the Wink RestClient to do functional testing on a Rest service endpoint. I use mocks for unit testing but I'd like to functionally test it as an endpoint consumer.
I understand some will object to me calling it a REST endpoint while using form-based auth but that is the current architecture I have.
The majority of the resources I want to test are protected resources and the application (running on Tomcat6) is protected by form authentication. (as in the below web.xml snippet).
What I've tried so far is to make an initial call to an unprotected resource, to obtain the set-cookie header, that contains JSESSIONID, and use that JSESSIONID in the header ( via Resource.cookie() ) in subsequent requests but that does not yield fruit.
web.xml
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/login.html</form-login-page>
<form-error-page>/login.html?failure=true</form-error-page>
</form-login-config>
</login-config>
My Wink RestClient code looks like below. All responses are 200, but two things I notice are that the response from the call to /j_security_check/ does not include the jsessionid cookie, and the call to the protected resource said I had a signin failure. The payload for the call to j_security_check was captured directly from a previous successful browser request intercepted.
ClientConfig config = new ClientConfig();
config.setBypassHostnameVerification(true);
RestClient restClient = new RestClient(config);
Resource unprotectedResource = restClient.resource( BASE_URL + "/");
unprotectedResource.header( "Accept", "*/*" );
ClientResponse clientResponse = unprotectedResource.get();
String response = clientResponse.getEntity(String.class);
// get jSession ID
String jSessionId = clientResponse.getHeaders().get("set-cookie").get(0);
jSessionId = jSessionId.split(";")[0];
System.out.println(jSessionId);
// create a request to login via j_security_check
Resource loginResource = restClient.resource(BASE_URL + "/j_security_check/");
loginResource.accept("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
loginResource.header("referer", "http://localhost:8080/contextroot/");
loginResource.cookie( jSessionId );
loginResource.header("Connection", "keep-alive");
loginResource.header("Content-Type", "application/x-www-form-urlencoded");
loginResource.header("Content-Length", "41");
ClientResponse loginResponse = loginResource.post("j_username=*****&j_password=*************");
/* the loginResponse, as this point, does not have the jsessionid cookie, my browser client does */
Resource protectedResource = restClient.resource(BASE_URL + "/protected/test/");
systemResource.accept("application/json");
systemResource.cookie( jSessionId );
ClientResponse systemResponse = systemResource.get();
response = clientResponse.getEntity(String.class);
System.out.println(response);
Any thoughts or experience with using the Wink RestClient to exercise form-auth-protected resources would be greatly appreciated. I suppose I'd entertain other frameworks, I have heard of REST-Assured and others, but since the application uses Wink and the RestClient seems to provide me with what I need, I figured I'd stick with it.
Found the problem, and the solution
j_security_check was responding to my POST request (to authenticate), with a #302/redirect. That was being followed by the wink RestClient, but my JSESSIONID cookie was not being appended to it. That was causing the response (from the redirected URL) to contain a set-cookie header, with a new header. My subsequent calls, into which I inserted the JSESSIONID from the first call, failed, because that cookie was expired. All I needed to do was instruct the RestClient to NOT follow redirects. If the redirect were necessary, I would construct it on my own, containing the appropriate cookie.
Chromium and Firefox carry the cookie from the original request to the redirected request so it's all good.
Here is some code that worked for me, using JUnit4, RestClient from the Apache Wink project (and a Jackson ObjectMapper)
#Test
public void testGenerateZipEntryName() throws JsonGenerationException, JsonMappingException, IOException
{
final ObjectMapper mapper = new ObjectMapper();
final String BASE_URL = "http://localhost:8080/rest";
// Configure the Rest client
ClientConfig config = new ClientConfig();
config.proxyHost("localhost"); // helpful when sniffing traffic
config.proxyPort(50080); // helpful when sniffing traffic
config.followRedirects(false); // This is KEY for form auth
RestClient restClient = new RestClient(config);
// Get an unprotected resource -- to get a JSESSIONID
Resource resource = restClient.resource( BASE_URL + "/");
resource.header( "Accept", "*/*" );
ClientResponse response = resource.get();
// extract the jSession ID, in a brittle and ugly way
String jSessId = response.getHeaders().get("set-cookie").get(0).split(";")[0].split("=")[1];
// Get the login resource *j_security_check*
resource = restClient.resource(BASE_URL + "/j_security_check");
resource.cookie("j_username_tmp=admin; j_password_tmp=; JSESSIONID=" + jSessId);
resource.header("Content-Type", "application/x-www-form-urlencoded");
resource.header("Content-Length", "41");
// Verify that login resource redirects us
response = resource.post("j_username=admin&j_password=***********");
assertTrue( response.getStatusCode() == 302 );
// Grab a public resource
resource = restClient.resource(BASE_URL + "/");
resource.cookie("j_username_tmp=admin; j_password_tmp=; JSESSIONID=" + jSessId);
response = resource.get();
// verify status of response
assertTrue( response.getStatusCode() == 200 );
// Grab a protected resource
resource = restClient.resource(BASE_URL + "/rest/system");
resource.cookie("j_username_tmp=admin; j_password_tmp=; JSESSIONID=" + jSessId);
// Verify resource returned OK
response = resource.contentType("application/json").accept("*/*").get();
assertTrue( response.getStatusCode() == 200 );
// Deserialize body of protected response into domain object for further testing
MyObj myObj = mapper.readValue(response.getEntity(String.class), MyObj.class );
assertTrue( myObj.customerArchived() == false );
}