I have a rather puzzling scenario right now, of figuring out how to integrate several large queries (many different items for each) into an iOS app that communicates with a C#-based REST API. I am trying to pull up several reports in the app, and if I recreate all these queries within the API along with recreating the interface in iOS, it could be quite time-consuming. The page that accesses the reports is a classic ASP page and includes a security header to ensure that the user session has been validated through the login page. Is there a way to set this up as a UIWebView and somehow validate a session upon loading of the UIWebView? Otherwise it will be quite a long, arduous process.
Could a cookie possibly be transferred over after the user has logged in using NSURLRequest to the UIWebView?
Each page has code to check if the session is authenticated
<%
if Session("portallogin") <> "good" then
response.redirect("example.com")
end if
%>
Here is some of the relevant login code that is responsible for initial authentication
'Get the username and password sent as well as user ip
On Error resume next
Session("login") = "bad" 'init to bad
sent_username = Request("username")
sent_password = Request("password")
source = Request.form("source")
remember_me = Request("remember_me")
userip = Request.ServerVariables("REMOTE_ADDR")
sent_username = replace(sent_username,"'","'")
sent_username = protectval(sent_username)
sent_password = protectval(sent_password)
if rs.BOF and rs.EOF then
Session("login") = "bad"
response.cookies("user")("name") = ""
response.Cookies("user")("pword") = ""
else
arr = rs.GetRows()
password = arr(0,0)
memberid = arr(1,0)
expired = arr(2,0)
if sent_password = password then
Session("login") = "good"
if expired = "True" Then
%>
'''''''''''''''''''
if session is good
'''''''''''''''''''
Session("username") = sent_username
Session("maintuser") = sent_username
Session("b2buser") = sent_username
Session("password") = sent_password
Session("memberid") = memberid
Session("customernumber") = customernumber
Session("cno") = cno
Session("login") = "good"
if remember_me = "on" Then
response.cookies("entry")("doorway") = cook(sent_username)
response.Cookies("entry")("michael") = cook(sent_password)
response.Cookies("entry")("remember_me") = cook("CHECKED")
Response.Cookies("entry").Expires = Now() + 365
else
response.cookies("entry")("doorway") = ""
response.Cookies("entry")("michael") = ""
response.Cookies("entry")("remember_me") = ""
Response.Cookies("entry").Expires = Now() + 5
end if
As most of the parameters reference the Request collection you could put the parameters in the querystring and thus make them part of the base url for UIWebView. So your URL request would look like
file.asp?username=xxx&password=yyy&source=zzz&remember_me=on
you would need to change line 7 in your sample file to be
source = Request("source")
but it would still work for existing requests.
The obvious problem with this code is that you have a username and password stored in your app which could be intercepted and abused. So be aware of that. I would not recommend this approach.
A better solution would be to consider rewriting the login function to store a temporary GUID and a timestamp in the database which could then be passed in the request as part of the querystring. Your authentication code could then be modified to check if that GUID is valid and update the timestamp associated with the GUID (or check for the session if they are using the old access method for that page).
Related
I set up an OpenBSD 7.0 instance on Vultr in order to get a mail server running with Dovecot and OpenSMTPD. I (mostly) followed the instructions here and here and a bit here.
I set it up to use with virtual mail, creating files in '/etc/mail/virtual' and '/etc/mail/credentials' with a single virtual user: 'user#domain.ca::vmail:2000:2000:/var/vmail/domain.ca/user::userdb_mail=maildir:/var/vmail/domain.ca/user'
I created the encrypted password with 'smtpctl encrypt' and pasted it where it should be in the credentials file.
However, running 'doveadm auth login user#domain.ca' fails.
In /var/log/maillog I get:
Jan 25 14:06:58 vultrBSD dovecot: auth-worker(165): conn unix:auth-worker (pid=44111,uid=518): auth-worker<1>: bsdauth(user#domain.ca): unknown user
Jan 25 14:06:58 vultrBSD dovecot: auth: passwd-file(user#domain.ca): Password mismatch
I know the password is correct, and I tried changing it and pasting in a new one that I created with 'smtpctl encrypt', but still the same error. The '/etc/mail/credentials' file is set to 0440 and owned by _smtpd:_dovecot. Even temporarily setting it to 0777 doesn't work.
I can send mail to the server from another account, I see that is shows up in '/var/vmail/domain.ca/user/new' but I am unable to connect my Thunderbird client to the server. Attempting to set up a new mail account in Thunderbird doesn't seem to work, Thunderbird rejects the password (although it does detect the correct protocols and ports, IMAP/SMTP).
Here is the local.conf file in /etc/dovecot:
auth_debug_passwords = yes
auth_mechanisms = plain
first_valid_uid = 2000
first_valid_gid = 2000
mail_location = maildir:/var/vmail/%d/%n
mail_plugin_dir = /usr/local/lib/dovecot
managesieve_notify_capability = mailto
managesieve_sieve_capability = fileinto reject envelope encoded-character vacation subaddress comparator-i;ascii-numeric relational regex imap4flags copy include variables body enotify environment mailbox date index ihave duplicate mime foreverypart extracttext imapsieve vnd.dovecot.imapsieve
mbox_write_locks = fcntl
mmap_disable = yes
namespace inbox {
inbox = yes
location =
mailbox Archive {
auto = subscribe
special_use = \Archive
}
mailbox Drafts {
auto = subscribe
special_use = \Drafts
}
mailbox Junk {
auto = subscribe
special_use = \Junk
}
mailbox Sent {
auto = subscribe
special_use = \Sent
}
mailbox Trash {
auto = subscribe
special_use = \Trash
}
prefix =
}
plugin {
imapsieve_mailbox1_before = file:/usr/local/lib/dovecot/sieve/report-spam.sieve
imapsieve_mailbox1_causes = COPY
imapsieve_mailbox1_name = Junk
imapsieve_mailbox2_before = file:/usr/local/lib/dovecot/sieve/report-ham.sieve
imapsieve_mailbox2_causes = COPY
imapsieve_mailbox2_from = Junk
imapsieve_mailbox2_name = *
sieve = file:~/sieve;active=~/.dovecot.sieve
sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.environment
sieve_pipe_bin_dir = /usr/local/lib/dovecot/sieve
sieve_plugins = sieve_imapsieve sieve_extprograms
}
protocols = imap sieve
service imap-login {
inet_listener imaps {
port = 993
}
}
service managesieve-login {
inet_listener sieve {
port = 4190
}
inet_listener sieve_deprecated {
port = 2000
}
}
ssl_cert = </etc/ssl/domain.ca.fullchain.pem
ssl_key = </etc/ssl/private/domain.ca.key
userdb {
args = username_format=%u /etc/mail/credentials
driver = passwd-file
name =
}
passdb {
args = scheme=CRYPT username_format=%u /etc/mail/credentials
driver = passwd-file
name =
}
protocol imap {
mail_plugins = " imap_sieve"
}
Has anyone else experienced this and know of a fix?
Thanks.
Hashed strings, including passwords, typically use several layers besides the base hashing algorithm. Two different implementations (dovecot vs smtpd) using the same hashing algorithm will output two different hashes given the same input (password.)
This is due to what is called salt and pepper. Salt is a randomly generated string usually based on some user data as the seed. This salt is then inserted into the password in a way dictated by the implementation (dovecot or smtpd) before hashing the password.
Similarly, pepper is a string dictated by the implementation and inserted into the password before hashing. This combination of salting and peppering creates a unique hash per implementation which makes storing passwords safer. This makes it so that a cracker can't easily compare hashes from several sites or programs to crack user passwords and break into all instances of that password simultaneously.
This is why you can't reuse a password hash stored by one program to unlock the same password when used by another program. Even if both programs use identical hashing algorithms.
The fix should be to set up the credentials individually for each program and not reuse each other's hashes.
I want to send email by connecting google via oauth
Below is the code present for C#
MailSender objMail = new MailSender();
objMail.TLS = true;
objMail.Username = "myaccount#gmail.com";
objMail.Password = "[oauth]ya29.Il-8B-88nf.......GhoNhUXKtBS-ZEQOAZ9tTWg";
...
objMail.Send();
For whole code please navigate to
https://www.aspemail.com/net_manual_03.html#3_5
To generate access token which is appended with "[oauth]" above, we are using
MailSender objMail = new MailSender();
MailSender objMail2 = objMail.GetAccessToken("GMAIL", "4/wQGBh....LtcM", false);
string AccessToken = objMail2.Username;
string RefreshToken = objMail2.Password;
int ExpiresIn = objMail2.Timeout;
I want to implement the same functionality in classic asp, but when i am creating object of "MailSender" in classic asp, it is throwing error that:
Object doesn't support this property or method:
'objMail.GetAccessToken'
Please suggest me how can i generate access token of oauth from classic asp
That error is telling you that the object you are using doesn’t recognise the method you are trying to call. In this situation the official documentation is the best resource.
Quote from GetAccessToken()
This method was introduced in version 5.5.0.1.
The likelihood here is you are using an older version of the ASPEmail COM component.
You can use the below code to output the version information;
<%
Dim Mail
Set Mail = Server.CreateObject("Persits.MailSender")
Call Response.Write("Version: " & Mail.Version)
%>
I am testing Account Kit (Basic Web version - phone number verification) on a Django (Python) based web app. One thing I try is logging with multiple accounts on localhost, and trying to link a different number to each one successively. If a number has already successfully attached to a previous account, I show an "already taken" error prompt. Standard stuff.
I've been noticing that I sporadically get the "already taken" error prompt on unused numbers as well. Investigating deeper, I found that although I had input and verified (via SMS) a new number, the account kit ID and mobile number returned to me was the previous pair.
I can't tell why this is happening. Can someone help me in debugging this? In case it matters, my authorization flow uses the app secret.
Following are some relevant snippets. First, the Account Kit Manager class I've written:
from myproj.account_kit_settings import FAID, AKAS
class AccountKitManager(object):
obj = None
def __init__(self, app_id, app_secret):
self.app_secret = app_secret
self.app_access_token = 'AA|{0}|{1}'.format(app_id, app_secret)
def get_user_cred(self, auth_code):
if not self.obj:
self.set_user_cred(auth_code)
return self.obj
def set_user_cred(self, auth_code, url=None):
if not url:
url = 'https://graph.accountkit.com/v1.2/access_token?grant_type=authorization_code&code={0}&access_token={1}&appsecret_proof={2}'.\
format(auth_code,self.app_access_token,self.get_appsecret_proof(self.app_access_token))
data = self.retrieve_data(url)
data = self.evaluate_data(data)
string_obj = self.retrieve_user_cred(data["access_token"])
self.obj = self.evaluate_data(string_obj)
def retrieve_user_cred(self, user_access_token, url=None):
if not url:
url = 'https://graph.accountkit.com/v1.2/me/?access_token={0}&appsecret_proof={1}'.\
format(user_access_token,self.get_appsecret_proof(user_access_token))
return self.retrieve_data(url)
def retrieve_data(self, url):
return requests.get(url).text
def evaluate_data(self, data):
return ast.literal_eval(data)
def get_appsecret_proof(self, access_token):
h = hmac.new(self.app_secret.encode('utf-8'),msg=access_token.encode('utf-8'),digestmod=hashlib.sha256)
return h.hexdigest()
Next, here's how I use it:
mobile_data = AccountKitManager(FAID, AKAS)
def account_kit_handshake(csrf, state, status, auth_code):
if csrf == state and status=='PARTIALLY_AUTHENTICATED':
user_data = mobile_data.get_user_cred(auth_code)
if FAID == user_data["application"]["id"]:
return user_data["id"], user_data["phone"]
else:
# app id mismatch
return None, None
else:
# csrf mismatch, or could not authenticate
return None, None
def get_requirements(request):
status = request.GET.get('status', None)
auth_code = request.GET.get('code', None)
state = request.GET.get('state', None)
return account_kit_handshake(request.session["csrf"], state, status, auth_code)
def verify_consumer_number(request,*args,**kwargs):
AK_ID, MN_data = get_requirements(request)
request.session.pop("csrf",None)
if AK_ID and MN_data:
if someone_elses_number(MN_data['national_number'], request.user.id):
return render(request,"used_number.html",{})
else:
save_consumer_credentials.delay(AK_ID, MN_data, request.user.id)
return redirect("classified_listing")
else:
return render(request,"unverified_number.html",{})
UPDATE: Seems the user access token isn't always being returned. This could be a problem with variable scope.
The problem emanated from the scope of the AccountKitManager class instance. It was being set globally (i.e. see mobile_data variable in my code). Making this variable local solved the problem.
I am using Google OAuth to authenticate the user in my GAE application. After the user clicks on "Grant Access", I want to return to my application. I tried setting the callback URL, but instead of being called independently, it gets appended to the current URL in the browser, and thus shows as an invalid URL.
Here is my code:
OAuthGetTemporaryToken requestToken = new OAuthGetTemporaryToken(REQUEST_TOKEN_URL);
requestToken.consumerKey = CONSUMER_KEY;
requestToken.transport = TRANSPORT;
requestToken.signer = signer;
requestToken.callback="www.mail.yahoo.com";
OAuthCredentialsResponse requestTokenResponse = requestToken.execute();
// updates signer's token shared secret
signer.tokenSharedSecret = requestTokenResponse.tokenSecret;
OAuthAuthorizeTemporaryTokenUrl authorizeUrl = new OAuthAuthorizeTemporaryTokenUrl(AUTHORIZE_URL);
authorizeUrl.temporaryToken = requestTokenResponse.token;
This line sends it to the Google OAuth page.
resp.sendRedirect(authorizeUrl.build());
I have set the callback parameter as shown above, but it's not working. Please help! Thanks in advance.
This is OAuth1 stuff, which is deprecated. Try using OAuth 2.0 instead. Start at https://developers.google.com/accounts/docs/OAuth2
I know how to generate a user key using the pastebin API, but how can I use this userkey to access a raw private paste?
I am using Lua for this.
Obtaining the raw paste bin output is not part of of the Pastebin API:
This option is actually not part of our API, but you might still want to use it. To get the RAW output of a paste you can use our RAW data output URL:
http://pastebin.com/raw.php?i=
Simply add the paste_key at the end of that URL and you will get the RAW output.
Since private pastes can only be seen by the user who created them, my guess is that they use the logincookie for authentication. In that case, you'll need to send it with the HTTP request.
In respect to implementing this in Lua, (since you haven't said which library you're using) I'm gonna go forth and recommend the HTTP module in LuaSocket or the wonderful Luvit (http://luvit.io).
Here is a ready example of the code for you:
local https = require('ssl.https')
https.TIMEOUT= 15
local private_raw_url="https://pastebin.com/raw/YOURPAGE" -- Change raw link
local user_name, user_password = "USER", "PASS" -- and user with password
local request_body = "submit_hidden=submit_hidden&user_name=".. user_name .. "&user_password=" .. user_password .. "&submit=Login"
local resp = {}
local res, code, headers, status = https.request ( {
method = 'POST',
url = "https://pastebin.com/login",
headers = {
Host = "pastebin.com",
["Content-Type"] = "application/x-www-form-urlencoded",
["Content-Length"] = string.len(request_body),
Connection = "keep-alive",
},
source = ltn12.source.string(request_body),
sink = ltn12.sink.table(resp),
protocol = "tlsv1",
verify = "none",
verifyext = {"lsec_continue", "lsec_ignore_purpose"},
options = { "all", "no_sslv2", "no_sslv3" }
} )
if not headers['set-cookie']:find('pastebin_user') then
print('bad login')
return
end
resp={}
local cookie = headers['set-cookie'] or ''
local cookie1, cookie2, cookie3 = cookie:match("(__cfduid=%w+; ).*(PHPSESSID=%w+; ).*(pastebin_user=%w+; )" )
if cookie1 and cookie2 and cookie3 then
cookie = cookie1 .. cookie2 .. cookie3
body, code, headers= https.request{
url = private_raw_url ,
headers = {
--Host = "pastebin.com",
['Cookie'] = cookie,
['Connection'] = 'keep-alive'
},
sink = ltn12.sink.table(resp)
}
if code~=200 then return end
print( table.concat(resp) )
else
print("error match cookies!" )
end
I know that this is a little late to answer the question but I hope this will help someone later on.
If you want to access raw private pastes, you will first need to list the pastes that the user has created. This is a part of the API. This requires the user to be logged in.
With this API you can list all the pastes created by a certain user.
You will need send a valid POST request to the URL below to access the
data:
http://pastebin.com/api/api_post.php
The response that you will get will be an XML response, as follows:
<paste>
<paste_key>0b42rwhf</paste_key>
<paste_date>1297953260</paste_date>
<paste_title>javascript test</paste_title>
<paste_size>15</paste_size>
<paste_expire_date>1297956860</paste_expire_date>
<paste_private>0</paste_private>
<paste_format_long>JavaScript</paste_format_long>
<paste_format_short>javascript</paste_format_short>
<paste_url>http://pastebin.com/0b42rwhf</paste_url>
<paste_hits>15</paste_hits>
</paste>
Once you have that, parse the XML to get the paste_key and the paste_private. You need to check the value of paste_private because you want private pastes only. The documentation says:
We have 3 valid values available which you can use with the
'api_paste_private' parameter:
0 = Public
1 = Unlisted
2 = Private (only allowed in combination with api_user_key, as you have to be logged into your account to access the paste)
So, if your paste has paste_private set to 2, get the paste_key for it.
Once you have the paste_key, use the API call to get the RAW paste. No username or password required once you have the paste key for the private paste.
Have fun!