DELPHI/INDY/IdHTTP Log into invision power board forum? - delphi

Need help keeping a session after logging into forum.
I'm using TIdHttp and have a cookie manager assigned already
Http.Get(Url); //..Used to get session Id that is then stored in FSessionID
Param := TStringList.Create;
Param.Add('act=Login');
Param.Add('CODE=01');
Param.Add('s='+FSessionID);
Param.Add('referer=''''');
Param.Add('CookieDate=1');
Param.Add('UserName=MYUsername');
Param.Add('PassWord=MyPassword');
Http.Post(Url,Param); //..The was Login succesfull. Made sure by checking responce
Http.Get(Url); //..Now its not logged in. Why????

Make sure the SessionID cookie is not being rejected by TIdCookieManager when it arrives. Indy's cookie support is currently broken, causing valid cookies to sometimes be ignored instead of stored.

It appears in your Post that you are providing the session as a parameter...which would make me assume that you would need to provide the session as a parameter in your Get as well. (The cookie doesn't appear to be used.)
Perhaps you include the session as part of the URL, as in:
Http.Get(URL + '?s=' + fSessionID)

Related

Kbmmw. Time out message "Anonymous user not authorized"

I made a new topic about my issue.
KIM told\
Anonymous requests typically means that it does not find a
username/password not a token in the clients request. Remember the
Token you get on your first request should be reused for all
subsequent requests by all client code (all kbmMWSimpleClient,
kbmMWClientQuery, kbmMWClientResolver etc). On way to centralize that
is to put a TkbmMWSimpleClient on the datamodule and specify all the
client query components to use this simple client instance as a
template. Then as the first thing before anything else in your client
application, make an initial "login" request call via the
simpleclient.
I changed ServerSideQueryAllClick on the client app. I copied Token from server side to client Edit1.text.
procedure TForm1.btnNamedServerSideQueryAllClick(Sender: TObject);
begin
// Gets all records from server event table.
If Length(Trim(Edit1.Text)) > 0 then
Begin
kbmMWSimpleClient1.Disconnect;
kbmMWSimpleClient1.Username:= CB1.Text; // Login -> Franz
kbmMWSimpleClient1.Password:= CB2.Text; // Password -> FranzPassword
kbmMWSimpleClient1.Token := Edit1.Text; // Token from server
kbmMWSimpleClient1.Connect;
End;
if qServerSide.Active then qServerSide.Close;
// Use named query.
qServerSide.Query.Text:='#ALL_EVENTS';
qServerSide.Open;
end;
It dowsn't work.
How to make relogin?
The Authorization demo shows how the client has a simpleclient that is used as template for all the client query components (by setting their Client property to point at the simpleclient instance).
When setting the token, you specifically do not want to set the username or password, and similarly if you are setting username and password, do not set the token.
Also make sure that qServerSide.Client points on your simpleclient.
Doing that you generally only need to setup username/password once on the simpleclient before anything is opened, then for example open the query component, after which the simpleclient.token value will automatically have been updated from the server with the assigned login token.

Message: ID4243: Could not create a SecurityToken. A token was not found in the token cache and no cookie was found in the context

We're getting the exact same error as in this thread ... in our production environment.
[WIF Security Token Caching
Does anybody have a fix to this error ?
Message: ID4243: Could not create a SecurityToken. A token was not found in the token cache and no cookie was found in the context.
Here is some info about our setup:
• We‘re using built-in Windows Identity Framework with .NET Framework 4.5.1
• The problem is almost always associated with changing from RelyingParty#X over to RelyingParty#Y ( e.g. the moment user clicks the RP#Y he‘s SIGNED OUT without asking for it ) – when he logs in again after this event, he‘s taken right to the page he was asking for, inside RP#Y
• We‘re using e.SessionToken.IsReferenceMode = true; // Cache on server, to get a smaller cookie
• By using IsReferenceMode = true, our FedAuth cookie stores a „pointer“ to the actual Token which is stored inside our database
• We‘re using our own DatabaseSecurityTokenCache which is overriding the functions in SessionSecurityTokenCache. By using the the DatabaseSecurityTokenCache alongside the IsSessionMode = true, we‘re server-farm-friendly ( but we‘re also guaranteed to be within the same server through all our login-session ) so if the application pool for some reason dies, we‘re able to get the token from database through the DatabaseSecurityTokenCache. I‘ve verified this by completely killing IIS in the middle of a session ( with „net stop WAS“ and the restart it again with „net start W3SVC“ and we‘re still able to get the Token from the DatabaseSecurityTokenCache ). I‘ve also tried doing the same by simply using the out-of-the-box SessionSecurityTokenCache and that will fail respectivly ( as expected )
• Default token lifetime is 20 minutes ( but the user can change it to 40 or 60 minutes if he wants to ) – that will only be effective the next time the user logs in ( and 90% of our user are just using the default 20 minutes lifetime )
• We‘re using a certificate (same on all servers) to encrypt the FedAuth cookie, NOT a machine-key ( which would be catastrophic if using server-farm, with different machine-keys )
• so all the servers can decrypt cookies, which were encrypted from another server.
• We have a javascript with a countdown in our RelyingParty4 and RelyingParty5 ( two different relying parties ) which is used as a „timeout script“ in case the user leaves his computer unattended ... he will be signed out when the token is about to expire – (minus) 30 seconds ( e.g. 20 minutes – 30 sec = 19,5 minutes ) with idle time. This is protect our very sensitive banking information, so when the user comes back to his machine he will need to login again. e.g. We‘re also using sliding sessions ([http://www.cloudidentity.com/blog/2013/05/08/sliding-sessions-for-wif-4-5/]) and when we slide, the timing in the javascript of the client is also updated as well, to match the length of the token minus 30 seconds. These 30 seconds are used to make sure that the session is still alive when signing out, so it‘s a little bit shorter than the lifetime of the token/session. We currently sliding if this condition is met: total lifetime / 2 .... e.g. 20 / 2
• We‘re only sliding if there‘s any activity going on with the user ( i.e. he‘s moving around, doing some work ). We're sliding in minute10+ (if token lifetime is 20minuts) as the example above shows
• We‘ve debugged the problem multiple times and this is the WIF error we‘re getting: Exception: System.IdentityModel.Tokens.SecurityTokenException Message: ID4243: Could not create a SecurityToken. A token was not found in the token cache and no cookie was found in the context. Source: Microsoft.IdentityModel at Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(XmlReader reader, SecurityTokenResolver tokenResolver) at Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(Byte[] token, SecurityTokenResolver tokenResolver) at Microsoft.IdentityModel.Web.SessionAuthenticationModule.ReadSessionTokenFromCookie(Byte[] sessionCookie) at Microsoft.IdentityModel.Web.SessionAuthenticationModule.TryReadSessionTokenFromCookie(SessionSecurityToken& sessionToken) at Microsoft.IdentityModel.Web.SessionAuthenticationModule.OnAuthenticateRequest(Object sender, EventArgs eventArgs) at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
• We‘ve been able to re-produce the bug by using an old FedAuth cookie and this plugin: ( attention! We‘re not sure if this is the same thing that‘s happening on PROD, but at least it gives the same error in our Logging system ) This is good, but I think you should add the steps on how we‘re able to modify the content of the FedAuth cookie, to bring this problem to life, locally.- You can use this:
It‘s simple by taking the Value of the FedAuth cookie from some previous sessions ( on the same machine! not from another machine, that won‘t work ) And pasting it into the Value of the FedAuth cookie and refreshing the page.-
Plugin used to modify the cookie, in Chrome is called „Edit This Cookie“:
- If we change the content of this cookie to a value from a previous session, and hit the refresh ( CTRL + R in Chrome ) we get the infamous TokenSecurityException ID4243 and the RP calls for a immidiate FederatedSignout because we're unable to recover from this situation.
Signing out....
I should also probably mention that we took's Microsoft MSDN's article marked "Important" on IsReferenceMode seriously and added it also to our
SessionAuthenticationModule_SessionSecurityTokenCreated event:
e.SessionToken.IsReferenceMode = true;
taken from MSDN:
Important!
To operate in reference mode, Microsoft recommends providing a handler for the WSFederationAuthenticationModule.SessionSecurityTokenCreated event in the global.asax.cs file and setting the SessionSecurityToken.IsReferenceMode property on the token passed in the SessionSecurityTokenCreatedEventArgs.SessionToken property. This will ensure that the session token operates in reference mode for every request and is favored over merely setting the SessionAuthenticationModule.IsReferenceMode property on the Session Authentication Module.
Below is our whole SessionAuthenticationModule_SessionSecurityTokenReceived,
please examine the comments I put into it ... it explains what everything does:
void SessionAuthenticationModule_SessionSecurityTokenReceived(object sender, SessionSecurityTokenReceivedEventArgs e)
{
if (e.SessionToken.ClaimsPrincipal != null)
{
DateTime now = DateTime.UtcNow;
DateTime validTo = e.SessionToken.ValidTo;
DateTime validFrom = e.SessionToken.ValidFrom;
TimeSpan lifespan = new TimeSpan(validTo.Ticks - validFrom.Ticks);
double keyEffectiveLifespan = new TimeSpan(e.SessionToken.KeyExpirationTime.Ticks - e.SessionToken.KeyEffectiveTime.Ticks).TotalMinutes;
double halfSpan = lifespan.TotalMinutes / 2;
if (validFrom.AddMinutes(halfSpan) < now && now < validTo)
{
SessionAuthenticationModule sam = sender as SessionAuthenticationModule;
// This will ensure a re-issue of the token, with an extended lifetime, ie "slide". Id deletes the current token from our databasetoken cache (with overriden Remove of the SessionSecurityTokenCache ) and writes a new one into the cache with the overriden AddOrUpdate of the SessionSecurityTokenCache.
// it will also write the token back into the cookie ( just the pointer to the cookie, because it's stored in database-cache ) because the IsReferenceMode = True is set
e.ReissueCookie = true; // Will force the DatabaseSecurityTokenCache'ið to clean up the cache with this, handler.Configuration.Caches.SessionSecurityTokenCache.Remove(key); internally in WIF's SessioAuthenticationModule
e.SessionToken = sam.CreateSessionSecurityToken(
e.SessionToken.ClaimsPrincipal,
e.SessionToken.Context,
now,
now.AddMinutes(lifespan.TotalMinutes),
false); // Make persistent, þannig að kakan lifir EKKI af browser-close / tab-lokun:
{
e.SessionToken.IsReferenceMode = true; // Cache on server
}
// Not needed, because if ReissueCookie = true; is set, it WILL to a WriteSessionTokenToCookie internally in WIF
//FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(e.SessionToken); // <---- er þetta e.t.v. bara það sem við þurfum ? Nei, á ekki að þurfa, er gert þegar tóki er búinn til með CreateSessionSecurityToken
}
else if (validTo < now)
{
// Fix
// http://blogs.planbsoftware.co.nz/?p=521
var sessionAuthenticationModule = (SessionAuthenticationModule)sender;
sessionAuthenticationModule.DeleteSessionTokenCookie(); // <--- is this really needed like the article says ? http://blogs.planbsoftware.co.nz/?p=521
e.Cancel = true; // This will allow a silent-login if the STS cookie is still valid, e.g. switching between RP's where we're switching from an active RP to a RP which has it's cookie outdated, but the STS's session is still alive. We don't want to prompt the user for a new login, beucase the STS session is still OK!
}
}
this post helped me, so it can help you and others those have this kind of error.
void Application_OnError()
{
var ex = Context.Error;
if (ex is SecurityTokenException){
Context.ClearError();
if (FederatedAuthentication.SessionAuthenticationModule != null){
FederatedAuthentication.SessionAuthenticationModule.SignOut();
}
Response.Redirect("~/");
}
}
From this link.
Hope it was useful!
---------- UPDATE, This is how Lord02 fixed the proplem -----------
The problem was that when users are coming in with stale cookies ( from a previous session, i.e. if they did NOT sign out from our system ... but instead just closed the tab ) and then logged in again,
our cookie which was in SessionMode = true ... tried to go to the DatabaseTokenCache to GET the whole token from database, but as I said our SSIS process deletes all Tokens which are OLDER than 12 hours old (outdated tokens!) so we don't have loads of orphan tokens, which are outdated in our database and are unusuable ... just taking up space in our database.
So after this deletion is done, each night, the DatabaseTokenCache GET‘s function would not return a valid Token ... and the user was signed out because of : ID4243: Could not create a SecurityToken. A token was not found in the token cache and no cookie was found in the context.
So instead of NOT deleting the Tokens inside our database I created a special handler, which intercepts this error on the RP‘s site ... and redirects the user back to the STS – which will then Create a brand new token and Write that down to the DatabaseTokenCacheStore, like this below
The exception with ID4243 is thrown when the cookie is set as “reference mode” AND the token is not present in the cache –
I can confirm that is by-design and also by-design WIF does not redirect the call to the STS (to start over the authentication process)
To overcome this problem I intercept this exception and react properly.
I redirect to the issuer if this error comes up inside a customSessionAuthModule I created for this:
public class CustomSessionAuthenticationModule : SessionAuthenticationModule
{
protected override void OnAuthenticateRequest(object sender, EventArgs eventArgs)
{
try
{
base.OnAuthenticateRequest(sender, eventArgs);
}
catch (SecurityTokenException exc)
{
// ID4243: Could not create a SecurityToken. A token was not found in the token cache and no cookie was found in the context.
if (exc.Message.IndexOf("ID4243", StringComparison.OrdinalIgnoreCase) >= 0)
{
// Returning directly without setting any token will cause the FederationAuthenticationModule
// to redirect back to the token issuer.
return;
}
else
{
throw;
}
}
}
}

Best way to upload files to Box.com programmatically

I've read the whole Box.com developers api guide and spent hours on the web researching this particular question but I can't seem to find a definitive answer and I don't want to start creating a solution if I'm going down the wrong path. We have a production environment where as once we are finished working with files our production software system zips them up and saves them into a local server directory for archival purposes. This local path cannot be changed. My question is how can I programmatically upload these files to our Box.com account so we can archive these on the cloud? Everything I've read regarding this involves using OAuth2 to gain access to our account which I understand but it also requires the user to login. Since this is an internal process that is NOT exposed to outside users I want to be able to automate this otherwise it would not be feasable for us. I have no issues creating the programs to trigger everytime a new files gets saved all I need is to streamline the Box.com access.
I just went through the exact same set of questions and found out that currently you CANNOT bypass the OAuth process. However, their refresh token is now valid for 60 days which should make any custom setup a bit more sturdy. I still think, though, that having to use OAuth for an Enterprise setup is a very brittle implementation -- for the exact reason you stated: it's not feasible for some middleware application to have to rely on an OAuth authentication process.
My Solution:
Here's what I came up with. The following are the same steps as outlined in various box API docs and videos:
use this URL https://www.box.com/api/oauth2/authorize?response_type=code&client_id=[YOUR_CLIENT_ID]&state=[box-generated_state_security_token]
(go to https://developers.box.com/oauth/ to find the original one)
paste that URL into the browser and GO
authenticate and grant access
grab the resulting URL: http://0.0.0.0/?state=[box-generated_state_security_token]&code=[SOME_CODE]
and note the "code=" value.
open POSTMAN or Fiddler (or some other HTTP sniffer) and enter the following:
URL: https://www.box.com/api/oauth2/token
create URL encoded post data:
grant_type=authorization_code
client_id=[YOUR CLIENT ID]
client_secret=[YOUR CLIENT SECRET]
code= < enter the code from step 4 >
send the request and retrieve the resulting JSON data:
{
"access_token": "[YOUR SHINY NEW ACCESS TOKEN]",
"expires_in": 4255,
"restricted_to": [],
"refresh_token": "[YOUR HELPFUL REFRESH TOKEN]",
"token_type": "bearer"
}
In my application I save both auth token and refresh token in a format where I can easily go and replace them if something goes awry down the road. Then, I check my authentication each time I call into the API. If I get an authorization exception back I refresh my token programmatically, which you can do! Using the BoxApi.V2 .NET SDK this happens like so:
var authenticator = new TokenProvider(_clientId, _clientSecret);
// calling the 'RefreshAccessToken' method in the SDK
var newAuthToken = authenticator.RefreshAccessToken([YOUR EXISTING REFRESH TOKEN]);
// write the new token back to my data store.
Save(newAuthToken);
Hope this helped!
If I understand correctly you want the entire process to be automated so it would not require a user login (i.e run a script and the file is uploaded).
Well, it is possible. I am a rookie developer so excuse me if I'm not using the correct terms.
Anyway, this can be accomplished by using cURL.
First you need to define some variables, your user credentials (username and password), your client id and client secret given by Box (found in your app), your redirect URI and state (used for extra safety if I understand correctly).
The oAuth2.0 is a 4 step authentication process and you're going to need to go through each step individually.
The first step would be setting a curl instance:
curl_setopt_array($curl, array(
CURLOPT_URL => "https://app.box.com/api/oauth2/authorize",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "content-type: application/x-www-form-urlencoded",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS =>
"response_type=code&client_id=".$CLIENT_ID."&state=".$STATE,
));
This will return an html text with a request token, you will need it for the next step so I would save the entire output to a variable and grep the tag with the request token (the tag has a "name" = "request_token" and a "value" which is the actual token).
Next step you will need to send another curl request to the same url, this time the post fields should include the request token, user name and password as follows:
CURLOPT_POSTFIELDS => "response_type=code&client_id=".$CLIENT_ID."&state=".$STATE."&request_token=".$REQ_TOKEN."&login=".$USER_LOGIN."&password=".$PASSWORD
At this point you should also set a cookie file:
CURLOPT_COOKIEFILE => $COOKIE, (where $COOKIE is the path to the cookie file)
This will return another html text output, use the same method to grep the token which has the name "ic".
For the next step you're going to need to send a post request to the same url. It should include the postfields:
response_type=code&client_id=".$CLIENT_ID."&state=".$STATE."&redirect_uri=".$REDIRECT_URI."&doconsent=doconsent&scope=root_readwrite&ic=".$IC
Be sure to set the curl request to use the cookie file you set earlier like this:
CURLOPT_COOKIEFILE => $COOKIE,
and include the header in the request:
CURLOPT_HEADER => true,
At step (if done by browser) you will be redirected to a URL which looks as described above:
http://0.0.0.0(*redirect uri*)/?state=[box-generated_state_security_token]&code=[SOME_CODE] and note the "code=" value.
Grab the value of "code".
Final step!
send a new cur request to https//app.box.com/api/oauth2/token
This should include fields:
CURLOPT_POSTFIELDS => "grant_type=authorization_code&code=".$CODE."&client_id=".$CLIENT_ID."&client_secret=".$CLIENT_SECRET,
This will return a string containing "access token", "Expiration" and "Refresh token".
These are the tokens needed for the upload.
read about the use of them here:
https://box-content.readme.io/reference#upload-a-file
Hope this is somewhat helpful.
P.S,
I separated the https on purpuse (Stackoverflow wont let me post an answer with more than 1 url :D)
this is for PHP cURL. It is also possible to do the same using Bash cURL.
For anyone looking into this recently, the best way to do this is to create a Limited Access App in Box.
This will let you create an access token which you can use for server to server communication. It's simple to then upload a file (example in NodeJS):
import box from "box-node-sdk";
import fs from "fs";
(async function (){
const client = box.getBasicClient(YOUR_ACCESS_TOKEN);
await client.files.uploadFile(BOX_FOLDER_ID, FILE_NAME, fs.createReadStream(LOCAL_FILE_PATH));
})();
Have you thought about creating a box 'integration' user for this particular purpose. It seems like uploads have to be made with a Box account. It sounds like you are trying to do an anonymous upload. I think box, like most services, including stackoverflow don't want anonymous uploads.
You could create a system user. Go do the Oauth2 dance and store just the refresh token somewhere safe. Then as the first step of your script waking up go use the refresh token and store the new refresh token. Then upload all your files.

CI 2.0.3 session heisenbug: session is lost after some time 20 minutes, only on server redirect, nothing suspicious in the logs

I can't seem to make any progress with this one. My CI session settings are these:
$config['sess_cookie_name'] = 'ci_session';
$config['sess_expiration'] = 0;
$config['sess_expire_on_close'] = FALSE;
$config['sess_encrypt_cookie'] = FALSE;
$config['sess_use_database'] = TRUE;
$config['sess_table_name'] = 'ci_sessions';
$config['sess_match_ip'] = FALSE;
$config['sess_match_useragent'] = FALSE;
$config['sess_time_to_update'] = 7200;
$config['cookie_prefix'] = "";
$config['cookie_domain'] = "";
$config['cookie_path'] = "/";
$config['cookie_secure'] = FALSE;
The session library is loaded on autoload. I've commented the sess_update function to prevent an AJAX bug that I've found about reading the CI forum.
The ci_sessions table in the database has collation utf8_general_ci (there was a bug that lost the session after every redirect() call and it was linked to the fact that the collation was latin1_swedish_ci by default).
It always breaks after a user of my admin section tries to add a long article and clicks the save button. The save action looks like this:
function save($id = 0){
if($this->my_model->save_article($id)){
$this->session->set_flashdata('message', 'success!');
redirect('admin/article_listing');
}else{
$this->session->set_flashdata('message', 'errors encountered');
redirect('admin/article_add');
}
}
If you spend more than 20minutes and click save, the article will be added but on redirect the user will be logged out.
I've also enabled logging and sometimes when the error occurs i get the message The session cookie data did not match what was expected. This could be a possible hacking attempt. but only half of the time. The other half I get nothing: a message that I've placed at the end of the Session constructor is displayed and nothing else. In all the cases if I look at the cookie stored in my browser, after the error the cookie's first part doesn't match the hash.
Also, although I know Codeigniter doesn't use native sessions, I've set session.gc_maxlifetime to 86400.
Another thing to mention is that I'm unable to reproduce the error on my computer but on all the other computers I've tested this bug appears by the same pattern as mentioned above.
If you have any ideas on what to do next, I'd greatly appreciate them. Changing to a new version or using a native session class (the old one was for CI 1.7, will it still work?) are also options I'm willing to consider.
Edit : I've run a diff between the Session class in CI 2.0.3 and the latest CI Session class and they're the same.
Here's how I solved it: the standards say that a browser shouldn't allow redirects after a POST request. CI's redirect() method is sending a 302 redirect by default. The logical way would be to send a 307 redirect, which solved my problem but has the caveat of showing a confirm dialog about the redirect. Other options are a 301 (meaning moved permanently) redirect or, the solution I've chosen, a javascript redirect.

How can my program log in to a Web site programmatically with Indy?

I am trying to log in to fileserve.com from my Delphi application.
I used the LiveHTTPHeader Firefox addon to see HTTP post data. I found
&autoLogin=on&recaptcha_response_field=&recaptcha_challenge_field=&recaptcha_shortencode_field=&loginFormSubmit=Login
I tried in my application like this:
Str := TStringList.Create;
Str.Add('loginUserName='+edit1.Text);
Str.Add('loginUserPassword='+edit2.Text);
Str.Add('autoLogin=on');
Str.Add('recaptcha_response_field=');
Str.Add('recaptcha_challenge_field=');
Str.Add('recaptcha_shortencode_field=');
Str.Add('loginFormSubmit=Login');
s:= IdHTTP1.Post('http://www.fileserve.com/login.php', Str);
FreeAndNil(str);
s1 := IdHTTP1.Get('http://www.fileserve.com/dashboard.php');
memo1.lines.add(s1);
In my my memo, it's not giving the data after I logged in. It just displays the source of the main site. Why doesn't it recognize that I logged in? (I used a working ID and password while testing.)
I am using Delphi 7 and Indy 9; The IdHTTP.HandleRedirect property is set to true.
The site you're logging in to probably sends a cookie in its response to the login request. You need to remember that cookie and send it back during all subsequent requests. Indy should have some sort of TIdCookieManager object that you can hook up to your TIdHTTP object to make it remember cookies automatically.

Resources