I'm new to AWS/S3 and following this tutorial from Amazon.
It's not working, and I'm wondering if it's due to the policy section.
Where does the policy go? For what it's worth, the form is in a React component. I tried putting the one below into the S3 policy in my AWS console, but it didn't like it.
I see the Access Key goes in the form. Where does the Secret key go? (Rails+React app)
Thanks for any guidance.
Here's the policy:
{ "expiration": "2007-12-01T12:00:00.000Z",
"conditions": [
{"bucket": "johnsmith"},
["starts-with", "$key", "user/eric/"],
{"acl": "public-read"},
{"success_action_redirect": "http://johnsmith.s3.amazonaws.com/successful_upload.html"},
["starts-with", "$Content-Type", "image/"],
{"x-amz-meta-uuid": "14365123651274"},
["starts-with", "$x-amz-meta-tag", ""]
]
}
And the form:
<form action="http://johnsmith.s3.amazonaws.com/" method="post" enctype="multipart/form-data">
Key to upload: <input type="input" name="key" value="user/eric/" /><br />
<input type="hidden" name="acl" value="public-read" />
<input type="hidden" name="success_action_redirect" value="http://johnsmith.s3.amazonaws.com/successful_upload.html" />
Content-Type: <input type="input" name="Content-Type" value="image/jpeg" /><br />
<input type="hidden" name="x-amz-meta-uuid" value="14365123651274" />
Tags for File: <input type="input" name="x-amz-meta-tag" value="" /><br />
<input type="hidden" name="AWSAccessKeyId" value="AKIAIOSFODNN7EXAMPLE" />
<input type="hidden" name="Policy" value="POLICY" />
<input type="hidden" name="Signature" value="SIGNATURE" />
File: <input type="file" name="file" /> <br />
<!-- The elements after this will be ignored -->
<input type="submit" name="submit" value="Upload to Amazon S3" />
</form>
...
The Policy value should be a base64-encoded version of your policy.
The Signature should be a hash based on the Policy and the Secret Key.
For example, this Python code (sorry, I don't have equivalent Ruby code handy) will output the two values for you:
#!/usr/bin/python
import base64
import hmac, hashlib
policy_document = '{ "expiration": "2007-12-01T12:00:00.000Z",
"conditions": [
{"bucket": "johnsmith"},
["starts-with", "$key", "user/eric/"],
{"acl": "public-read"},
{"success_action_redirect": "http://johnsmith.s3.amazonaws.com/successful_upload.html"},
["starts-with", "$Content-Type", "image/"],
{"x-amz-meta-uuid": "14365123651274"},
["starts-with", "$x-amz-meta-tag", ""]
]
}'
AWS_SECRET_ACCESS_KEY = "<SECRET-KEY>"
policy = base64.b64encode(policy_document)
signature = base64.b64encode(hmac.new(AWS_SECRET_ACCESS_KEY, policy, hashlib.sha1).digest())
print policy
print
print signature
Everything in your form looks alright, except POLICY & SIGNATURE:
Policy will be encoded as Base64 which includes some basic info about bucket, expiration, acl, etc,..
Signature will be encoded as Base64 as well which includes secret key, and above policy
Here is my example which describes how to generate POLICY & SIGNATURE:
class S3Upload
attr_reader :policy_document, :signature
def initialize
#policy_document = generate_policy_document
#signature = generate_signature
end
private
def generate_policy_document
Base64.encode64(
{
expiration: 1.day.from_now.utc.strftime('%Y-%m-%dT%H:%M:%S.000Z'),
conditions: [
{ bucket: YOUR_BUCKET },
{ acl: 'public-read' },
["starts-with", "$key", ""],
{ success_action_status: '201' },
["starts-with","$content-type", "image/"]
]
}.to_json
).gsub(/\n|\r/, '')
end
def generate_signature
Base64.encode64(
OpenSSL::HMAC.digest(
OpenSSL::Digest::Digest.new('sha1'),
YOUR_AWS_SECRET_ACCESS_KEY,
policy_document
)
).gsub(/\n/, '')
end
end
You can use this class to export policy & signature, then include to your form.
We don't include secret key to form directly, we use it to generate signature as my example above
Related
I am trying to use the Switch User feature of grails using the documentation
application.groovy changes:
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
[pattern: '/j_spring_security_switch_user', access: ['ROLE_TENANT_ADMIN']],
[pattern: '/j_spring_security_exit_user', access: ['permitAll']]
]
grails.plugin.springsecurity.switchUser.targetUrl = "/public/landing"
grails.plugin.springsecurity.useSwitchUserFilter = true
Also overridden the SwitchUser Filter since my role in the application is different from the ROLE_SWITCH_USER using the link
But whenever I click on the Switch form I am facing 403 Forbidden
<sec:ifAllGranted roles="ROLE_TENANT_ADMIN">
<form action="/j_spring_security_switch_user" method="POST">
Switch to user: <input name="j_username" type="text"
value="###email####">
<input type="submit" value="Switch"> </form>
</sec:ifAllGranted>
I have a React Login component running on localhost:3000. It returns a form which, on submit, uses JS fetch() to post its information to SessionsController in a rails api which runs on localhost:3001. I've alternated between using a FormData object and custom json; I run into the same problems either way. I've gotten rid of CORS errors in the console by using 'rack-cors', but I'm still having problems accessing the posted information in my SessionController's create action. This is all I have in params when I throw a binding.pry into it:
[1] pry(#<SessionsController>)> params
=> <ActionController::Parameters {"controller"=>"sessions",
"action"=>"create"} permitted: false>
------- How do I get hold of my username and password? ----------
Login Component:
import React from 'react'
const Login = () => {
return(
<div>
<h1>Login</h1>
<form id="login-form" onSubmit={(event) => postSession(event)}>
<label htmlFor="username">Username </label><br/>
<input type="text" id="username"/><br/>
<label htmlFor="password">Password </label><br/>
<input type="password" id="password"/><br/>
<input type="submit" value="Login"/>
</form>
</div>
)
}
const postSession = (event) => {
event.preventDefault()
fetch('http://localhost:3001/sessions',
{
header: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
method: 'post',
body: new FormData(document.getElementById("login-form"))
}
)
.then((response) => {console.log("Post Session Response: ", response)})
.catch((error) => {console.log("Error in the Post Session fetch: ", error)})
}
export default Login
config/application.js:
module Geohunter2
class Application < Rails::Application
config.middleware.insert_before 0, "Rack::Cors" do
allow do
origins '*'
resource '*', :headers => :any, :methods => [:get, :post, :patch, :options]
end
end
end
end
You need name attributes on your form inputs:
<input type="text" id="username" name="user[username]"/><br/>
...
<input type="text" id="password" name="user[password]"/><br/>
Then you'll have access to params[:user][:username] params[:user][:password] in your controller.
Assuming you're using strong_params in a newer version of Rails (4+), you'll also need something like this in your controller action.
def new # or whatever action you're posting
Session.create(user_params)
end
private
def user_params
params.require(:user).permit(:username, :password)
end
This is my login form. If a user puts in a wrong username and does not exists on the server then how do I use md-error to display message?
E.g.
Here is the json I get back for auth from a submit:
{is_username: false, status: false}
Here is how I set up my form:
this.myForm = fb.group({
username: ['',[Validators.required]],
password: ['',[Validators.required]]
})
Here is my HTML:
<md-input-container>
<input mdInput type="email" placeholder="Username" [(ngModel)]="username" formControlName="username" style="width: 300px;outline: none;">
<md-error *ngIf="myForm.get('username').hasError('required')">Username is required</md-error>
<md-error *ngIf="myForm.get('username').hasError('username_exists')">Username does exist</md-error>
</md-input-container>
So..how do I trigger a md-error message if is_username is false?
I've been doing server side validation like this.
<md-input-container>
<input mdInput type="email" placeholder="Username" [(ngModel)]="username" formControlName="username" style="width: 300px;outline: none;">
<md-error *ngIf="myForm.get('username').hasError('required')">Username is required</md-error>
<md-error *ngIf="myForm.controls['username'].hasError('username_exists')">{{myForm.controls['username'].errors['username_exists']}}</md-error>
</md-input-container>
Then, set the error after you get the response from the server.
https://angular.io/api/forms/AbstractControl#setErrors
this.myForm.controls['username'].setErrors({
'username_exists': 'Username does exist'
});
I typically return validation error messages from the server as well, which could be used here.
I've configured the CAS login page so that it accepts the username and password as GET parameters and if these are provided, it submits the login form automatically. This looks as the CAS login page is not even touched during authentication from the website.
The website is using phpCAS version 1.3.2 to communicate with CAS. If I log in directly through the form, It works as expected: the browser gets redirected back from CAS correctly and isAuthenticated() returns true. However if I log in to a different service beforehand, isAuthenticated() returns false. If I'm not mistaken this is because I have to do an actual check with CAS if the auth is fine, therefore I've also tried checkAuthentication(), but I get the following errors:
[error] [client 192.168.12.120] PHP Fatal error: Uncaught exception 'CAS_AuthenticationException' in /home/dev/www/CAS-1.3.2/CAS/Client.php:2248
Stack trace:
#0 /home/dev/www/CAS-1.3.2/CAS/Client.php(1227): CAS_Client->_validatePGT('https://192.168...', '????<cas:servic...', Object(DOMElement))
#1 /home/dev/www/CAS-1.3.2/CAS/Client.php(1131): CAS_Client->isAuthenticated()
#2 /home/dev/www/CAS-1.3.2/CAS.php(1078): CAS_Client->checkAuthentication()
#3 /home/dev/www/redir.php(39): phpCAS::checkAuthentication()
#4 {main}
thrown in /home/dev/www/CAS-1.3.2/CAS/Client.php on line 2248, referer: https://192.168.10.144:8181/cas/login?username=myUser&password=testpassword&auto=true&service=https%3A%2F%2F192.168.12.120%2Fredir.php
CAS server log
phpCAS debug log
PHP Code:
<?php
function pageURL() {
$PROTOCOL = "http";
if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') {
$PROTOCOL = "https";
}
$url = "$PROTOCOL://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
$url = strtok($url, '?');
return $url;
}
// Configuration
$phpcas_path = "CAS-1.3.2";
$cas_host = "192.168.10.144";
$cas_port = 8181;
$cas_context = "/cas";
// Load the CAS lib
require_once $phpcas_path . "/CAS.php";
// Enable debugging
phpCAS::setDebug ();
// Initialize phpCAS
phpCAS::proxy ( CAS_VERSION_2_0, $cas_host, $cas_port, $cas_context );
phpCAS::setNoCasServerValidation ();
// check CAS authentication
$auth = phpCAS::checkAuthentication();
// logout if desired
if (isset ( $_REQUEST ['logout'] )) {
phpCAS::logout ();
}
$serviceUrl = "https://192.168.10.144:8181/accessrights/";
?>
<html>
<head>
<title>CAS form login</title>
</head>
<body>
<?php if ($auth) {
phpCAS::serviceWeb($serviceUrl, $err_code, $accessrights);
?>
<p>Hello <strong><?php echo phpCAS::getUser(); ?></strong>! You have been authenticated with CAS. Your access rights are: <?php echo $accessrights; ?></p>
<?php } else { ?>
<h3>User login</h3>
<div>Enter your username and password here in order to log in on the website:</div>
<!-- ###LOGIN_FORM### -->
<form method="GET" action="https://192.168.10.144:8181/cas/">
<p>Username : <input type="text" name="username" /></p>
<p>Password : <input type="password" name="password" /></p>
<p>Remember me : <input type="checkbox" name="rememberMe" value="true" /></p>
<p><input type="submit" value="Login !" /></p>
<input type="hidden" name="auto" value="true" />
<input type="hidden" name="service" value="<?php echo pageURL(); ?>" />
</form>
<!-- ###LOGIN_FORM### -->
<?php } ?>
</body>
</html>
I see that checkAuthentication() fails to retrieve a Proxy Granting Ticket, but I have no clue about the reason. Any ideas? I also have a page with forceAuthentication(), and it works flawlessly.
According to your server's log, CAS is trying to callback your application via "https://xxx.xx.xx.xx/redir.php" but his encounter an SSL issue "TicketCreationException: error.authentication.credentials.bad"
I'm using express and having trouble getting form data from the bodyParser. No matter what I do it always comes up as an empty object. Here is my express generated app.js code (the only thing I added was the app.post route at the bottom):
var express = require('express');
var app = module.exports = express.createServer();
// Configuration
app.configure(function(){
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(__dirname + '/public'));
});
app.configure('development', function(){
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.configure('production', function(){
app.use(express.errorHandler());
});
// Routes
app.get('/', function(req, res){
res.sendfile('./public/index.html');
});
app.post('/', function(req, res){
console.log(req.body);
res.sendfile('./public/index.html');
});
app.listen(3010);
Here is my HTML form:
<!doctype html>
<html>
<body>
<form id="myform" action="/" method="post" enctype="application/x-www-form-urlencoded">
<input type="text" id="mytext" />
<input type="submit" id="mysubmit" />
</form>
</body>
</html>
When I submit the form, req.body is an empty object {}
Its worth noting that this happens even if I remove the enctype attribute from the form tag
...Is there something I am missing/doing wrong?
I am using node v0.4.11 and express v2.4.6
<form id="myform" action="/" method="post" enctype="application/x-www-form-urlencoded">
<input type="text" name="I_appear_in_req_body" id="mytext" />
<input type="submit" id="mysubmit" />
</form>
The body of a HTTP post is a key/value hash of all the form controls with a name attribute, and the value is the value of the control.
You need to give names to all your inputs.
It also due to content type. please see console.log(req) object.
'content-type': 'application/json; charset=UTF-8’ // valid.
'content-type': 'application/JSON; charset=UTF-8’ // invalid & req.body would empty object {}.
To check content type by console.log(req.is('json')) // return true/false
I think 'charset=UTF-8' is negligible in above.
If your form looks like this
<form action="/", method="post">
<label for="for_name">Name: </label>
<input id="for_name" type="text" name="user_name"/>
<button type="submit">Submit</button>
</form>
And if you are using the following line of code
app.use(express.json());
then the req.body will be empty because it only parses req with content-type application/json but the default value of request originating from element is application/x-www-form-urlencoded. Hence the following line of code will solve the issue
app.use(express.urlencoded({ extended: true }));
My first StackOverflow contribution. Yay!!