Asking extra password when using scp - bash

I'm not sure if I should be asking this here or in Server Fault, feel free to flag the question and migrate it if necessary.
I have some servers which I would like to add an extra security layer. Actually we are using key authentication with passphrase.
We bought some Yubikeys (OTP password generator) that I would like to use. I created a system that validates the Yubikey and that the owner of the Yubikey is authorized to login. In order to use this system I created the ~/.ssh/rc where I ask the user to press the Yubikey and then I use a remote server to validate it.
So far so good, it works perfectly when trying to login via ssh. Here comes the problem: when I try to scp to a server that has this extra protection it throws the following error:
/dev/tty: No such device or address
The error is thrown by the line where I ask the user to enter the OTP:
read -sp "Press your Yubikey..." OTP < /dev/tty
This doesn't happen when I ssh from one server to another that has this extra protection.

scp doesn't start an interactive session so there isn't a terminal to connect to (and so no /dev/tty to read from).
You need to detect that and not try to read from it in that case.
That being said this is likely the wrong way to have gone about doing this. ssh is most likely configured on your system to use pam and there is a pam module for yubikey that can be used to use a yubikey as part of the ssh authentication for an account. See https://developers.yubico.com/yubico-pam/ for the basics.
Their configuration uses the yubikey as the only authentication you will need to configure pam slightly differently to get it to be an additional piece of required login information instead. (Assuming, of course, that you want this to work for the scp case instead of just skipping it for the scp case.)

As pointed out by Etan, you really should just use PAM for this.
Note that you don't have to ask for the user to press the Yubikey either. The pam_yubico.so module will pass through anything you type before the challenge response to the next module in the PAM stack. Look at the try_first_pass flag in pam_unix(8) for instance.
Just type the password, don't press enter, then press the Yubikey.
You can implement your own module to do the database check. Writing PAM modules isn't that hard.
Something like this in /etc/pam.d/sshd:
# auth
auth requisite /usr/local/lib/security/pam_yubico.so id=[yours] key=[yours] authfile=/etc/yubikey_mappings
auth required pam_unix.so no_warn try_first_pass
Try logging in:
% slogin hogfather
YubiKey for `philip': [password][yubikey]
Last login: Thu Mar 5 01:13:55 2015 from twoflower.trouble.is

OK, you want the yubikey authentication plus an authorization, that checks, whether the user is allowed to login at this server.
You might want to take a look at privacyIDEA.
This is an OTP authentication backend. You can even initialize your yubikeys if you like to. Use pam_radius to forward the auth request to privacyIDEA. (no hassle with scp).
privacyIDEA can
check the OTP value of the yubikey AND
use policies to check, if the user is allowed to login on that machine with this token type or token serial number. see readthedocs

Related

Pubnub Auth Key and Auth Key Safety (Grant Token)

I have stuck in here and couldn't find a solid solution.
I use PHP in server-side and Vanilla JS in the client side.
In server-side, I'm generating a auth token (https://www.pubnub.com/docs/general/basics/manage-access) for current logged in user's channel to make him able to read his channel messsages by the following code:
I'm also generating a new one when the key timeout so all OK with the generation.
But my problem is starts here:
I'm passing the key into the client like this:
And user is getting access to the channel. But the thing is, I'm passing this auth key to the client-side. Which is someone that get this user's auth token; can setup their own client and can read messages that sent to this user.
How can I deal with that?
And another one:
I'm publishing to a channel in PHP like this. But I'm able do to that without setting auth token. I'm sure auth token system is working because when I pass wrong auth key to the client it's giving 403 forbidden. But however, I'm able to publish to channel without auth key in here. Is this because it's server-side?
Thanks!
Googled everything...
someone that get this user's auth token; can setup their own client and can read messages that sent to this user
This authorization strategy is the same as JWT. How will someone get this auth token? If you are using a secure connection to your server (TSL, aka https), and your PHP server is secured, then that is all you can do. This is the internet :)
Now how secure is the end user's machine? Are they susceptible to phishing or other schemes that might allow a hacker to gain access to their machine? Humans are the easiest thing to hack and you can't really do anything to secure them ;)
So as far as PubNub is concerned with security, you are doing exactly what very large companies have been doing for over 10 years with PubNub. The question is how secure is your server that a hacker can't get access to your code and data and get your PubNub secret key. In my 9+ years at PubNub, I've never known this to happen.
granting permissions on your channel
You are granting too many permissions but it doesn't have any negative side effects.
read - subscribe (receive messages), fetch (messages from history), and some presence stuff (get/set state, here now)
write - publish (send messages)
get and set - this is for PubNub Objects only which is different than pub/sub.
Again, no harm comes from granting permissions that have no effect on the resources you are granting to but it adds to the size of the auth token (just a little bit in this case).
able do to that without setting auth token
When you do setToken you are setting that on the pubnub object that you use to invoke PubNub operations. The PubNUb SDK automatically adds the auth token as a query parameter in the request. So it is being passed automatically for you.
Open your browser console, select the Network tab, and look at any PubNub request/url. You will see the query parameter names auth and the value is your auth token.
PubNub Secret Key give you all access
The secret key gives your server the ability to grant permissions (generate an auth token) AND it gives your server all access to all things in your PubNub key set. Don't let that secret key get compromised.

Setting up authentication/authorization using Traefik ForwardAuth

I'm using Docker to setup some services and Traefik 2 acts as a reverse proxy for these services.
So far I was using Basic Auth to protect the access to the services, but I'm trying to get rid of the user/pass prompt.
Looking at the Traefik's documentation, I found the "ForwardAuth" middleware which seems fine. I'm planning to use it to replace Basic Auth, but a full implementation example is not provided as an example, and I'm having a hard time trying to set it up.
So far, thanks to Traefik forward-auth, I'm successfully calling a specific URL on a remote server in charge of the authentication (this server is developped with Spring Boot by myself). I understand that if the authentication server answers 200, it means "authentication success" while another code means "authentication failure".
Yet, I'm currently unable to write the authentication code on the remote server as I don't know how to check if I must return 200 or something else. Especially I don't know how to communicate information between Traefik and the authentication server.
Basically, the problems I have are:
I can't ask the user for his/her username/password using Traefik
When the authentication server receives the request from Traefik, it has no way to define that the source request was a previously authenticated user
The following picture shows most of my concerns:
What I'd like to achieve is the following behavior:
The user tries to access to the Docker services without entering any username/password
Traefik determines that the user is not authenticated, thanks to forward-auth it asks the authentication server for authentication
The authentication server determines that the user is not authenticated, the user is redirected to the login page
The user enters his/her username/password on the authentication server
The user is redirected to the Docker services
Traefik determines that the user is authenticated
So far, I can successfully achieve step 1 to 5, but I don't know how to achieve step 6.
Is this the right way to use ForwardAuth?
If it is, are there some headers I must use to transfer the auth information? If not, is it possible to achieve what I want using ForwardAuth?
As far as i understand, traefik also forwards Any headers accompaning the original request. If you are not filtering Any. see docs traefik forward-auth.

Spring Cloud Config with Github repo using Credentials

I am trying to access the Github repo which sits behind an enterprise firewall (Open VPN). I am trying to access with my username and password but getting the below Exception. Any suggestions on how to access the repo with Spring Cloud.
application.properties:
spring.cloud.config.server.git.uri=https://github.com/company-repo/abc.git
spring.cloud.config.server.git.username=tarun
spring.cloud.config.server.git.password=xxxxx
spring.cloud.config.server.git.ignore-local-ssh-settings=true
Exception:
Error occured cloning to base directory. org.eclipse.jgit.api.errors.TransportException:
https://github.com/company-repo/abc.git: not authorized
Do not Use Your GitHub password in your app.prop file...You will get a Not Authorized exception. Instead Generate an access token.
Creating a personal access token
You should create a personal access token to use in place of a password with the command line or with the API.
Personal access tokens (PATs) are an alternative to using passwords for authentication to GitHub when using the GitHub API or the command line.
If you want to use a PAT to access resources owned by an organization that uses SAML SSO, you must authorize the PAT. For more information, see "About authentication with SAML single sign-on" and "Authorizing a personal access token for use with SAML single sign-on."
As a security precaution, GitHub automatically removes personal access tokens that haven't been used in a year.
Creating a token
Verify your email address, if it hasn't been verified yet.
In the upper-right corner of any page, click your profile photo, then click Settings.
Settings icon in the user bar
In the left sidebar, click Developer settings.
In the left sidebar, click Personal access tokens.
Click Generate new token.
Give your token a descriptive name.
Select the scopes, or permissions, you'd like to grant this token. To use your token to access repositories from the command line, select repo.
Click Generate token.
Click to copy the token to your clipboard. For security reasons, after you navigate off the page, you will not be able to see the token again.
Warning: Treat your tokens like passwords and keep them secret. When working with the API, use tokens as environment variables instead of hardcoding them into your programs.
To use your token to authenticate to an organization that uses SAML SSO, authorize the token for use with a SAML single-sign-on organization.
Using a token on the command line
Once you have a token, you can enter it instead of your password when performing Git operations over HTTPS.
For example, on the command line you would enter the following:
$ git clone https://github.com/username/repo.git
Username: your_username
Password: your_token
Personal access tokens can only be used for HTTPS Git operations. If your repository uses an SSH remote URL, you will need to switch the remote from SSH to HTTPS.
If you are not prompted for your username and password, your credentials may be cached on your computer. You can update your credentials in the Keychain to replace your old password with the token.
The way i made it work is :
Generate the Access Token on Github repo and provide read and admin rights to it
Use the Token as password
Credentials can be saved in Kubernetes as Secrets or inside Vault. Hope this helps.

How to validate user's cached credentials against a domain?

When you logon to Windows, your credentials are cached. This allows you to use single sign-on. If you were to then browse to another computer, e.g.:
\\hydrogen
you would not be prompted for credentials.
Windows will take your:
current username
(hashed) password
and attempt to authenticate you automatically. The interesting thing is that this even works if your workstation is not on the domain. Windows will automatically use your username and password when connecting to the server. And if your:
local username/password matches a
domain username/password
you are automatically let in.
Pretty picture:
This is called Single Sign-On. You sign-on to Windows once, and your cached credentials are used to validate you as you use other things on the network.
Browsers also do this
Chrome, Internet Explorer, and Firefox also do a variation of this. If you need to login to a web-site, and the server supports Negotiation authorization, the server will send you back an indication that you should try the user's Windows/Domain/Kerberos credentials:
HTTP/1.1 401 Unauthorized
Server: Microsoft-IIS/7.5
WWW-Authenticate: Negotiate
Date: Thu, 09 Jul 2015 14:35:58 GMT
Content-Length: 0
Chrome will then take your cached credentials, and (after some intermediate magic) forward them to the web-server:
GET http://hr.woodglue.com HTTP/1.1
Host: hr.woodglue.com
Authorization: Negotiate YIIFzwYGKwYBBQUCoIIFwzCCBb....
Microsoft talks about this mechanism in Internet Explorer in the old article:
HTTP-Based Cross-Platform Authentication by Using the Negotiate Protocol
The client calls AcquireCredentialsHandle() and InitializeSecurityContext() with the SPN to build the Security Context that requests the session ticket from the TGS/KDC.
You validate against a domain, not servers
A final point i want to mention is that servers, web-servers, workstations, file servers, don't validate credentials against a server, they validate against a domain controller. You have a nebulous forest of many domain servers, and one of them handles your request.
In other words, you don't validate credentials against:
\\uranium (a domain controller on the woodglue.com domain)
you validate credentials against:
the woodglue.com domain
We have the important concept that someone can:
validate your cached credentials
against a domain
without having to enter a username or password
How can I do this?
How can I validate someone's cached credentials? How can I:
validate the user's cached credentials
against a domain
without the user having to enter a username or password (i.e. using the Windows cached credentials)
The important point is that is don't know (or care):
if the user's machine is joined to a domain
if the user's machine is joined to a workgroup
if the user's machine is joined to the woodglue.com or some other domain (e.g. superglue.com)
the names of the servers that power the superglue.com domain
I don't know how to do it.
I don't know what API technologies are involved.
I know there is an API called the Security Support Provider Interface (SSPI). This is what powers WWW-Authenticate: Negotiate (although i don't know if it is what powers SMB from a non-domain joined PC).
Chromium's open-source might be able to start us off with a snippet from their http_auth_sspi_win.cc. They use the SSPI function AcquireCredentialsHandle:
int AcquireDefaultCredentials(CredHandle* cred)
{
TimeStamp expiry;
// Pass the username/password to get the credentials handle.
// Note: Since the 5th argument is NULL, it uses the default
// cached credentials for the logged in user, which can be used
// for a single sign-on.
SECURITY_STATUS status = library->AcquireCredentialsHandle(
NULL, // pszPrincipal
const_cast<SEC_WCHAR*>(package), // pszPackage
SECPKG_CRED_OUTBOUND, // fCredentialUse
NULL, // pvLogonID
NULL, // pAuthData
NULL, // pGetKeyFn (not used)
NULL, // pvGetKeyArgument (not used)
cred, // phCredential
&expiry); // ptsExpiry
}
Pass the username/password to get the credentials handle.
Note: Since the 5th argument is NULL, it uses the default cached credentials for the logged in user, which can be used for a single sign-on.
This "outbound" call to AcquireCredentialsHandle is followed up by a call to InitializeSecurityContext. The idea is that InitializeSecurityContext generates an opaque blob that represents the client.
You can then perform a parallel set of calls:
"inbound" call to AcquireCredentialsHandle
call AcceptSecurityContext, passing the blob returned earlier from InitializeSecurityContext
To steal rehost Daniel Doubrovkine's excellent image:
Note: In this case "client" and "server" are used to refer to context of producer and consumer. In my case the "client" and "server" are on the same machine.
But this line of "shows research effort" falls apart because i don't see anywhere in InitializeSecurityContext where i can specify woodglue.com as the domain to validate against.
I know that InitializeSecurityContext contacts a kerberos server, and obtains a "ticket" blob. That ticket blob is then passed to the "server" through AcceptSecurityContext. Sometimes the blob can be passed over a network; in my case it is passed around in memory on the same machine.
But i don't see how to specify the domain server that it should be contacting for that ticket.
Not to imply that SSPI is at all useful to solve my problem. It's just "research effort".
Older Research Effort
What TargetName to use when calling InitializeSecurityContext (Negotiate)?
How to validate domain credentials (from native code)?
Validate a user's password using the hash?
Win32: How to validate credentials against Active Directory?
How to perform Windows Authentication?
Of course, during all this, if the cached credentials are not valid on the specified domain, i would have to prompt the user for a username and password. But usernames and passwords are evil, the bane of computing, and i want to avoid them.
i'm using native code; not C#.

How to pass over an authentication window from within Bash Terminal?

Suppose there are some web sites that require people to type in his or her username and/or password to pass through the authentication dialog to get the actual contents behind it. When people encounter such web sites on a browser he or she can type in his or her username and/or password to pass through the authentication. However, is it feasible to verify it from within Terminal?
The content there is a single zip file, and I was able to download it using curl and -u option to specify my username. However, it still requires me to type in my password to pass through the authentication, and I would like to know how to automatically go through it using my password, without being prompted to type in my password, since I have to download it every day, and want to use my bash script to achieve it.
I use OS X 10.9.2 and I would like to access it from within my Terminal. I have both of my username and password on the authentication for sure. I might be interested to know the most secure way possible to pass through the verification.
You should be able to use curl for this, just change the argument you give for -u to include the password:
curl -u username:password http://www.website.com/content/file.zip
Obviously this requires storing your password in plaintext in your script, which is not ideal for security. If you have SSH access to the server in question, you can create a private/public key pair, then use the public key to log into the server without a password being required (and download the file using scp), which would ideal from a security point of view.

Resources